diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 5af35168e3..4e63263cd5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -399,7 +399,7 @@ object ValDefn: // * a lone module is represented as an empty class with a `companion` module. final case class ClsLikeDefn( owner: Opt[InnerSymbol], - isym: MemberSymbol[? <: ClassLikeDef] & InnerSymbol, + isym: DefinitionSymbol[? <: ClassLikeDef] & InnerSymbol, sym: BlockMemberSymbol, k: syntax.ClsLikeKind, paramsOpt: Opt[ParamList], @@ -414,12 +414,12 @@ final case class ClsLikeDefn( bufferable: Option[Bool], ) extends Defn: require(k isnt syntax.Mod) - val innerSym = S(isym) + val innerSym = S(isym.asMemSym) // * This is only supposed to be for companion module definitions (notably, not for `object`) final case class ClsLikeBody( - isym: MemberSymbol[? <: ModuleOrObjectDef] & InnerSymbol, + isym: DefinitionSymbol[? <: ModuleOrObjectDef] & InnerSymbol, methods: Ls[FunDefn], privateFields: Ls[TermSymbol], publicFields: Ls[BlockMemberSymbol -> TermSymbol], @@ -497,7 +497,7 @@ sealed abstract class Result extends AutoLocated: case Lambda(params, body) => params :: Nil case Tuple(mut, elems) => elems.map(_.value) case Record(mut, elems) => elems.map(_.value) - case Value.Ref(l) => Nil + case Value.Ref(l, disamb) => Nil case Value.This(sym) => Nil case Value.Lit(lit) => lit :: Nil @@ -518,7 +518,7 @@ sealed abstract class Result extends AutoLocated: case Tuple(mut, elems) => elems.flatMap(_.value.freeVars).toSet case Record(mut, args) => args.flatMap(arg => arg.idx.fold(Set.empty)(_.freeVars) ++ arg.value.freeVars).toSet - case Value.Ref(l) => Set(l) + case Value.Ref(l, disamb) => Set(l) case Value.This(sym) => Set.empty case Value.Lit(lit) => Set.empty case DynSelect(qual, fld, arrayIdx) => qual.freeVars ++ fld.freeVars @@ -531,11 +531,11 @@ sealed abstract class Result extends AutoLocated: case Tuple(mut, elems) => elems.flatMap(_.value.freeVarsLLIR).toSet case Record(mut, args) => args.flatMap(arg => arg.idx.fold(Set.empty)(_.freeVarsLLIR) ++ arg.value.freeVarsLLIR).toSet - case Value.Ref(l: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | TermSymbol)) => Set.empty - case Value.Ref(l: MemberSymbol[?]) => l.defn match + case Value.Ref(l: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | TermSymbol), disamb) => Set.empty + case Value.Ref(l: MemberSymbol[?], disamb) => l.defn match case Some(d: ClassLikeDef) => Set.empty case _ => Set(l) - case Value.Ref(l) => Set(l) + case Value.Ref(l, disamb) => Set(l) case Value.This(sym) => Set.empty case Value.Lit(lit) => Set.empty case DynSelect(qual, fld, arrayIdx) => qual.freeVarsLLIR ++ fld.freeVarsLLIR @@ -560,19 +560,38 @@ case class Record(mut: Bool, elems: Ls[RcdArg]) extends Result sealed abstract class Path extends TrivialResult: def selN(id: Tree.Ident): Path = Select(this, id)(N) - def sel(id: Tree.Ident, sym: FieldSymbol): Path = Select(this, id)(S(sym)) + def sel(id: Tree.Ident, sym: DefinitionSymbol[?]): Path = Select(this, id)(S(sym)) def selSN(id: Str): Path = selN(new Tree.Ident(id)) def asArg = Arg(spread = N, this) -case class Select(qual: Path, name: Tree.Ident)(val symbol: Opt[FieldSymbol]) extends Path with ProductWithExtraInfo: - def extraInfo: Str = symbol.mkString +/** + * @param symbol The symbol representing the definition that the selection refers to, if known. + */ +case class Select(qual: Path, name: Tree.Ident)(val symbol: Opt[DefinitionSymbol[?]]) extends Path with ProductWithExtraInfo: + def extraInfo: Str = symbol.map(s => s"sym=${s}").mkString case class DynSelect(qual: Path, fld: Path, arrayIdx: Bool) extends Path -enum Value extends Path: - case Ref(l: Local) +enum Value extends Path with ProductWithExtraInfo: + /** + * @param disamb The symbol disambiguating the definition that the reference refers to. This + * exists if and only if l is a BlockMemberSymbol. + */ + case Ref(l: Local, disamb: Opt[DefinitionSymbol[?]]) case This(sym: InnerSymbol) // TODO rm – just use Ref case Lit(lit: Literal) + + override def extraInfo: Str = this match + case Ref(l, disamb) => disamb.map(s => s"disamb=${s}").mkString + case _ => "" + +object Value: + object Ref: + // * Some helper constructors that allow omitting the disambiguation symbol. + // * If the ref itself is a DefinitionSymbol, then disambiguating it results in itself. + def apply(l: DefinitionSymbol[?]): Ref = Ref(l, S(l)) + // * If the ref is a symbol that does not refer to a definition, then there is no disambiguation. + def apply(l: TempSymbol | VarSymbol | BuiltinSymbol): Ref = Ref(l, N) case class Arg(spread: Opt[Bool], value: Path) @@ -603,6 +622,6 @@ extension (k: Block => Block) def blockBuilder: Block => Block = identity extension (l: Local) - def asPath: Path = Value.Ref(l) + def asPath: Path = Value.Ref(l, N) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTransformer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTransformer.scala index 21cf08a8da..a5d94dfaa6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTransformer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTransformer.scala @@ -144,9 +144,9 @@ class BlockTransformer(subst: SymbolSubst): case v: Value => applyValue(v)(k) def applyValue(v: Value)(k: Value => Block) = v match - case Value.Ref(l) => + case Value.Ref(l, disamb) => val l2 = l.subst - k(if (l2 is l) then v else Value.Ref(l2)) + k(if (l2 is l) then v else Value.Ref(l2, disamb)) case Value.This(sym) => val sym2 = sym.subst k(if (sym2 is sym) then v else Value.This(sym2)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTraverser.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTraverser.scala index 3bbfff1abe..8f68ac00ba 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTraverser.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/BlockTraverser.scala @@ -69,7 +69,7 @@ class BlockTraverser: case v: Value => applyValue(v) def applyValue(v: Value): Unit = v match - case Value.Ref(l) => l.traverse + case Value.Ref(l, disamb) => l.traverse case Value.This(sym) => sym.traverse case Value.Lit(lit) => () diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/BufferableTransform.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/BufferableTransform.scala index f4c49abdc4..95a229f6d7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/BufferableTransform.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/BufferableTransform.scala @@ -57,7 +57,7 @@ class BufferableTransform()(using Ctx, State, Raise): fieldMap.get(sym).orElse(pubFieldMap.get(sym).flatMap(fieldMap.get(_))).fold(super.applyPath(p)(k)): off => getOffset(off): res => k(res) - case Value.Ref(l) => + case Value.Ref(l, _) => fieldMap.get(l).fold(super.applyPath(p)(k)): off => getOffset(off): res => k(res) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/HandlerLowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/HandlerLowering.scala index 6fe5bb8510..3393ec5b6c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/HandlerLowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/HandlerLowering.scala @@ -33,7 +33,7 @@ object HandlerLowering: private case class LinkState(res: Local, cls: Path, uid: Path) - type FnOrCls = Either[BlockMemberSymbol, MemberSymbol[? <: ClassLikeDef] & InnerSymbol] + type FnOrCls = Either[BlockMemberSymbol, DefinitionSymbol[? <: ClassLikeDef] & InnerSymbol] // isTopLevel: // whether the current block is the top level block, as we do not emit code for continuation class on the top level @@ -132,7 +132,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, def apply(res: Local, uid: StateId, rest: Block) = Assign(res, PureCall(Value.Ref(resumptionSymbol), List(Value.Lit(Tree.IntLit(uid)))), rest) def unapply(blk: Block) = blk match - case Assign(res, PureCall(Value.Ref(`resumptionSymbol`), List(Value.Lit(Tree.IntLit(uid)))), rest) => + case Assign(res, PureCall(Value.Ref(`resumptionSymbol`, _), List(Value.Lit(Tree.IntLit(uid)))), rest) => Some(res, uid, rest) case _ => None @@ -141,7 +141,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, def apply(res: Local, uid: StateId) = Assign(res, PureCall(Value.Ref(returnContSymbol), List(Value.Lit(Tree.IntLit(uid)))), End("")) def unapply(blk: Block) = blk match - case Assign(res, PureCall(Value.Ref(`returnContSymbol`), List(Value.Lit(Tree.IntLit(uid)))), _) => + case Assign(res, PureCall(Value.Ref(`returnContSymbol`, _), List(Value.Lit(Tree.IntLit(uid)))), _) => Some(res, uid) case _ => None @@ -157,7 +157,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, def unapply(blk: Block) = blk match case Assign( res, - PureCall(Value.Ref(`callSymbol`), List(Value.Lit(Tree.IntLit(uid)))), + PureCall(Value.Ref(`callSymbol`, _), List(Value.Lit(Tree.IntLit(uid)))), Assign(_, c, rest)) => Some(res, uid, c, rest) case _ => None @@ -167,7 +167,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, def apply(uid: StateId) = Return(PureCall(Value.Ref(transitionSymbol), List(Value.Lit(Tree.IntLit(uid)))), false) def unapply(blk: Block) = blk match - case Return(PureCall(Value.Ref(`transitionSymbol`), List(Value.Lit(Tree.IntLit(uid)))), false) => + case Return(PureCall(Value.Ref(`transitionSymbol`, _), List(Value.Lit(Tree.IntLit(uid)))), false) => S(uid) case _ => N @@ -175,7 +175,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, private val fnEndSymbol = freshTmp("fnEnd") def apply() = Return(PureCall(Value.Ref(fnEndSymbol), Nil), false) def unapply(blk: Block) = blk match - case Return(PureCall(Value.Ref(`fnEndSymbol`), Nil), false) => true + case Return(PureCall(Value.Ref(`fnEndSymbol`, _), Nil), false) => true case _ => false private class FreshId: @@ -522,7 +522,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, ResultPlaceholder(res, freshId(), c2, k(Value.Ref(res))) case r => super.applyResult(r)(k) override def applyPath(p: Path)(k: Path => Block): Block = p match - case Value.Ref(`getLocalsSym`) => k(handlerCtx.debugInfo.prevLocalsFn.get) + case Value.Ref(`getLocalsSym`, _) => k(handlerCtx.debugInfo.prevLocalsFn.get) case _ => super.applyPath(p)(k) override def applyLam(lam: Lambda): Lambda = // This should normally be unreachable due to prior desugaring of lambda @@ -591,7 +591,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, f.owner match case None => S(Call(f.sym.asPath, params)(true, true)) case Some(owner) => - S(Call(Select(owner.asPath, Tree.Ident(f.sym.nme))(S(f.sym)), params)(true, true)) + S(Call(Select(owner.asPath, Tree.Ident(f.sym.nme))(N), params)(true, true)) case _ => None // TODO: more than one plist FunDefn(f.owner, f.sym, f.params, translateBlock(f.body, @@ -657,7 +657,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, handler.sym, handler.params, Define( fDef, - Return(PureCall(paths.mkEffectPath, h.cls.asPath :: Value.Ref(sym) :: Nil), false))) + Return(PureCall(paths.mkEffectPath, h.cls.asPath :: Value.Ref(sym, N) :: Nil), false))) // Some limited handling of effects extending classes and having access to their fields. // Currently does not support super() raising effects. @@ -687,7 +687,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, val body = blockBuilder .define(clsDefn) - .assign(h.lhs, Instantiate(mut = true, Value.Ref(clsDefn.sym), Nil)) + .assign(h.lhs, Instantiate(mut = true, Value.Ref(clsDefn.sym, S(h.cls)), Nil)) .rest(handlerBody) val defn = FunDefn( @@ -735,7 +735,7 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, val transform = new BlockTransformerShallow(SymbolSubst()): override def applyResult(r: Result)(k: Result => Block): Block = r match - case c @ Call(Value.Ref(s: BuiltinSymbol), _) => () + case c @ Call(Value.Ref(s: BuiltinSymbol, _), _) => () case c: Call if !c.mayRaiseEffects => () case _: Call | _: Instantiate => containsCall = true case _ => () @@ -792,7 +792,8 @@ class HandlerLowering(paths: HandlerPaths, opt: EffectHandlers)(using TL, Raise, override def applyBlock(b: Block): Block = b match case ReturnCont(res, uid) => Return(Call( Select(clsSym.asPath, Tree.Ident("doUnwind"))( - N /* this refers to the method defined in Runtime.FunctionContFrame */ ), + N /* this refers to the method defined in Runtime.FunctionContFrame */ + ), res.asPath.asArg :: Value.Lit(Tree.IntLit(uid)).asArg :: Nil)(true, false), false ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/LambdaRewriter.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/LambdaRewriter.scala index 9bd10e89dc..1a64cdd855 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/LambdaRewriter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/LambdaRewriter.scala @@ -28,7 +28,7 @@ object LambdaRewriter: case lam: Lambda => val sym = BlockMemberSymbol("lambda", Nil, nameIsMeaningful = false) lambdasList ::= (sym -> super.applyLam(lam)) - k(Value.Ref(sym)) + k(Value.Ref(sym, N)) case _ => super.applyResult(r)(k) val blk = lambdaRewriter.applyBlock(b) (blk, lambdasList) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lifter.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lifter.scala index 9af128304d..db70913ea2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lifter.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lifter.scala @@ -101,17 +101,17 @@ object Lifter: case s: LocalVarSymbol => s object RefOfBms: - def unapply(p: Path) = p match - case Value.Ref(l: BlockMemberSymbol) => S(l) + def unapply(p: Path): Opt[(BlockMemberSymbol, Opt[DefinitionSymbol[?]])] = p match + case Value.Ref(l: BlockMemberSymbol, disamb) => S((l, disamb)) case s @ Select(_, _) => s.symbol match - case Some(value: BlockMemberSymbol) => S(value) + case Some(value) => value.asBlkMember.map((_, S(value))) case _ => N case _ => N object InstSel: def unapply(p: Path) = p match - case Value.Ref(l: BlockMemberSymbol) => S(l) - case s @ Select(Value.Ref(l: BlockMemberSymbol), Tree.Ident("class")) => S(l) + case Value.Ref(l: BlockMemberSymbol, _) => S(l) + case s @ Select(Value.Ref(l: BlockMemberSymbol, _), Tree.Ident("class")) => S(l) case _ => N def modOrObj(d: Defn) = d match @@ -175,7 +175,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): val isymPaths: Map[InnerSymbol, LocalPath] = Map.empty, val replacedDefns: Map[BlockMemberSymbol, Defn] = Map.empty, val firstClsFns: Set[BlockMemberSymbol] = Set.empty, - val companionMap: Map[InnerSymbol, InnerSymbol] = Map.empty + val companionMap: Map[InnerSymbol, InnerSymbol] = Map.empty, ): // gets the function to which a local belongs def lookup(l: Local) = usedLocals.lookup(l) @@ -230,11 +230,11 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): enum LocalPath: case Sym(l: Local) - case PubField(isym: MemberSymbol[? <: ClassLikeDef] & InnerSymbol, sym: BlockMemberSymbol) + case PubField(isym: DefinitionSymbol[? <: ClassLikeDef] & InnerSymbol, sym: BlockMemberSymbol) def read = this match case Sym(l) => l.asPath - case PubField(isym, sym) => Select(isym.asPath, Tree.Ident(sym.nme))(S(sym)) + case PubField(isym, sym) => Select(isym.asPath, Tree.Ident(sym.nme))(N) def asArg = read.asArg @@ -242,7 +242,11 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case Sym(l) => Assign(l, value, rest) case PubField(isym, sym) => AssignField(isym.asPath, Tree.Ident(sym.nme), value, rest)(S(sym)) - + def readDisamb(d: Opt[DefinitionSymbol[?]]) = this match + case Sym(l) => Value.Ref(l, d) + case PubField(isym, sym) => Select(isym.asPath, Tree.Ident(sym.nme))(d) + + def isHandlerClsPath(p: Path) = handlerPaths match case None => false case Some(paths) => paths.isHandlerClsPath(p) @@ -449,7 +453,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case _ => () override def applyResult(r: Result): Unit = r match - case Call(Value.Ref(_: BlockMemberSymbol), args) => + case Call(Value.Ref(_: BlockMemberSymbol, _), args) => args.foreach(applyArg) case Instantiate(mut, InstSel(_), args) => args.foreach(applyArg) @@ -473,9 +477,9 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): parentPath match case None => () case Some(path) if isHandlerClsPath(path) => () - case Some(Select(RefOfBms(s), Tree.Ident("class"))) => + case Some(Select(RefOfBms(s, _), Tree.Ident("class"))) => if clsSyms.contains(s) then extendsGraph += (s -> defn.sym) - case Some(RefOfBms(s)) => + case Some(RefOfBms(s, _)) => if clsSyms.contains(s) then extendsGraph += (s -> defn.sym) case _ if !ignored.contains(defn.sym) => raise(WarningReport( @@ -500,14 +504,14 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case _ => false override def applyValue(v: Value): Unit = v match - case RefOfBms(l) if clsSyms.contains(l) && !modOrObj(ctx.defns(l)) => + case RefOfBms(l, _) if clsSyms.contains(l) && !modOrObj(ctx.defns(l)) => raise(WarningReport( msg"Cannot yet lift class `${l.nme}` as it is used as a first-class class." -> N :: Nil, N, Diagnostic.Source.Compilation )) ignored += l unliftable += l - case RefOfBms(l) if ctx.defns.contains(l) && isFun(ctx.defns(l)) => + case RefOfBms(l, _) if ctx.defns.contains(l) && isFun(ctx.defns(l)) => // naked reference to a function definition firstClsFns += l case _ => super.applyValue(v) @@ -554,11 +558,9 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): val clsCaptures: List[InnerSymbol] = ctx.prevClsDefns.map(_.isym) val refBms = inScopeRefs.intersect(ctx.ignoredDefns).toList.sortBy(_.uid) - val modLocal = d match - case c: ClsLikeDefn if modOrObj(c) && !ctx.ignored(c.sym) => parentCls match - case None => S(VarSymbol(Tree.Ident(c.sym.nme + "$"))) - case Some(value) => S(TermSymbol(syntax.ImmutVal, S(value.isym), Tree.Ident(c.sym.nme + "$"))) - case _ => N + val isModLocal = d match + case c: ClsLikeDefn if modOrObj(c) && !ctx.ignored(c.sym) => true + case _ => false if ctx.ignored(d.sym) || (includedCaptures.isEmpty && includedLocals.isEmpty && clsCaptures.isEmpty && refBms.isEmpty) then @@ -570,7 +572,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case _ => Map.empty else val fakeCtorBms = d match - case c: ClsLikeDefn if !modLocal.isDefined => S(BlockMemberSymbol(d.sym.nme + "$ctor", Nil)) + case c: ClsLikeDefn if !isModLocal => S(BlockMemberSymbol(d.sym.nme + "$ctor", Nil)) case _ => N val singleCallBms = BlockMemberSymbol(d.sym.nme + "$", Nil) @@ -629,7 +631,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): override def applyResult(r: Result)(k: Result => Block): Block = r match // if possible, directly rewrite the call using the efficient version - case c @ Call(RefOfBms(l), args) => ctx.bmsReqdInfo.get(l) match + case c @ Call(RefOfBms(l, _), args) => ctx.bmsReqdInfo.get(l) match case Some(info) if !ctx.isModOrObj(l) => val extraArgs = ctx.defns.get(l) match // If it's a class, we need to add the isMut parameter. @@ -656,7 +658,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): // extract the call override def applyPath(p: Path)(k: Path => Block): Block = p match - case RefOfBms(l) if ctx.bmsReqdInfo.contains(l) && !ctx.isModOrObj(l) => + case RefOfBms(l, disamb) if ctx.bmsReqdInfo.contains(l) && !ctx.isModOrObj(l) => val newSym = closureMap.get(l) match case None => // $this was previously used, but it may be confused with the `this` keyword @@ -672,7 +674,7 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case Some(value) => syms.addOne(l -> value) value - k(Value.Ref(newSym)) + k(Value.Ref(newSym, disamb)) case _ => super.applyPath(p)(k) (walker.applyBlock(b), syms.toList) end rewriteBms @@ -763,15 +765,16 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case _ => super.applyBlock(rewritten) // rewrite object definitions, assigning to the given symbol in modObjLocals - case Define(d: Defn, rest: Block) => ctx.modObjLocals.get(d.sym) match + case Define(d: ClsLikeDefn, rest: Block) => ctx.modObjLocals.get(d.sym) match case Some(sym) if !ctx.ignored(d.sym) => ctx.getBmsReqdInfo(d.sym) match case Some(_) => // has args blockBuilder .assign(sym, Instantiate(mut = false, d.sym.asPath, getCallArgs(d.sym, ctx))) .rest(applyBlock(rest)) case None => // has no args + // Objects with no parameters are instantiated statically blockBuilder - .assign(sym, Instantiate(mut = false, d.sym.asPath, Nil)) + .assign(sym, d.sym.asPath) .rest(applyBlock(rest)) case _ => ctx.replacedDefns.get(d.sym) match case Some(value) => Define(value, applyBlock(rest)) @@ -784,11 +787,11 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): override def applyPath(p: Path)(k: Path => Block): Block = p match // These two cases rewrites `this.whatever` when referencing an outer class's fields. - case Value.Ref(l: InnerSymbol) => + case Value.Ref(l: InnerSymbol, _) => ctx.resolveIsymPath(l) match case Some(value) if !iSymInScope(l) => k(value.read) case _ => super.applyPath(p)(k) - case Value.Ref(t: TermSymbol) if t.owner.isDefined => + case Value.Ref(t: TermSymbol, _) if t.owner.isDefined => ctx.resolveIsymPath(t.owner.get) match case Some(value) if !iSymInScope(t.owner.get) => if (t.k is syntax.LetBind) && !t.owner.forall(_.isInstanceOf[semantics.TopLevelSymbol]) then @@ -799,30 +802,25 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): )) k(Select(value.read, t.id)(N)) case _ => super.applyPath(p)(k) - - // Rewrites this.className.class to reference the top-level definition - case s @ Select(RefOfBms(l), Tree.Ident("class")) if !ctx.ignored(l) && ctx.isRelevant(l) => - // this class will be lifted, rewrite the ref to strip it of `Select` - k(Select(Value.Ref(l), Tree.Ident("class"))(s.symbol)) // For objects inside classes: When an object is nested inside a class, its defn will be // replaced by a symbol, to which the object instance is assigned. This rewrites references // from the objects BlockMemberSymbol to that new symbol. case s @ Select(qual, ident) => s.symbol.flatMap(ctx.getLocalPath) match - case Some(LocalPath.Sym(value: MemberSymbol[?])) => + case Some(LocalPath.Sym(value: DefinitionSymbol[?])) => k(Select(qual, Tree.Ident(value.nme))(S(value))) case _ => super.applyPath(p)(k) // This is to rewrite references to classes that are not lifted (when their BlockMemberSymbol // reference is passed as function parameters). - case RefOfBms(l) if ctx.ignored(l) && ctx.isRelevant(l) => ctx.getIgnoredBmsPath(l) match - case Some(value) => k(value.read) + case RefOfBms(l, disamb) if ctx.ignored(l) && ctx.isRelevant(l) => ctx.getIgnoredBmsPath(l) match + case Some(value) => k(value.readDisamb(disamb)) case None => super.applyPath(p)(k) // This rewrites naked references to locals. If a function is in a capture, then we select that value // from the capture; otherwise, we see if that local is passed directly as a parameter to this defn. - case Value.Ref(l) => ctx.getLocalCaptureSym(l) match + case Value.Ref(l, _) => ctx.getLocalCaptureSym(l) match case Some(captureSym) => k(Select(ctx.getLocalClosPath(l).get.read, captureSym.id)(N)) case None => ctx.getLocalPath(l) match @@ -1024,9 +1022,8 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): val isMutSym = VarSymbol(Tree.Ident("isMut")) var curSym = TempSymbol(None, "tmp") - def instInner(isMut: Bool) = if c.paramsOpt.isDefined - then Instantiate(mut = isMut, Select(c.sym.asPath, Tree.Ident("class"))(N), paramArgs) - else Instantiate(mut = isMut, c.sym.asPath, paramArgs) + def instInner(isMut: Bool) = + Instantiate(mut = isMut, Value.Ref(c.sym, S(c.isym)), paramArgs) val initSym = curSym @@ -1110,10 +1107,12 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): // ctorIncluded: ditto, but lifted val (ctorIgnored, ctorIncluded) = allCtorDefns.partition(d => ctxx.ignored(d.sym)) + // Symbols containing refernces to nested classes and nested objects are here + // Deals with references to lifted objects defined within the class val nestedClsPaths: Map[Local, LocalPath] = ctorIncluded.map: case c: ClsLikeDefn if modOrObj(c) => ctxx.modObjLocals.get(c.sym) match - case Some(sym) => S(c.sym -> LocalPath.Sym(sym)) + case Some(sym) => S(c.isym -> LocalPath.Sym(sym)) case _ => S(c.sym -> LocalPath.Sym(c.sym)) case _ => None .collect: @@ -1186,11 +1185,9 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case d => d def rewriteExtends(p: Path): Path = p match - case RefOfBms(b) if !ctx.ignored(b) && ctx.isRelevant(b) => b.asPath - case Select(RefOfBms(b), Tree.Ident("class")) if !ctx.ignored(b) && ctx.isRelevant(b) => - Select(b.asPath, Tree.Ident("class"))(N) + case RefOfBms(b, _) if !ctx.ignored(b) && ctx.isRelevant(b) => b.asPath case _ => return p - + // if this class extends something, rewrite val newPar = c.parentPath.map(rewriteExtends) @@ -1279,7 +1276,8 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): .withCompanionMap(analyzer.companionMap) val walker1 = new BlockTransformerShallow(SymbolSubst()): - override def applyBlock(b: Block): Block = b match + override def applyBlock(b: Block): Block = + b match case Define(d, rest) => val LifterMetadata(unliftable, modules, objects, firstClsFns) = createMetadata(d, ctx) @@ -1288,7 +1286,11 @@ class Lifter(handlerPaths: Opt[HandlerPaths])(using State, Raise): case Some(bms) => val nestedIn = analyzer.defnsMap(bms) nestedIn match - case cls: ClsLikeDefn => S(c.sym -> TermSymbol(syntax.ImmutVal, S(cls.isym), Tree.Ident(c.sym.nme + "$"))) + // These will be the names of the objects/modules after being lifted + // We should use the nested object/module's **original name** if nested inside a class, + // so they can be accesed directly by name from the outside. + // For example, if a class C has an object M, (new C).M as a dynamic selection works + case cls: ClsLikeDefn => S(c.sym -> TermSymbol(syntax.ImmutVal, S(cls.isym), Tree.Ident(c.sym.nme))) case _ => S(c.sym -> VarSymbol(Tree.Ident(c.sym.nme + "$"))) case _ => N .collect: diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala index 1cce08105d..a54d543674 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Lowering.scala @@ -45,7 +45,7 @@ class Subst(initMap: Map[Local, Value]): Subst(map + kv) */ def apply(v: Value): Value = v match - case Value.Ref(l) => map.getOrElse(l, v) + case Value.Ref(l, _) => map.getOrElse(l, v) case _ => v object Subst: val empty = Subst(Map.empty) @@ -313,6 +313,79 @@ class Lowering()(using Config, TL, Raise, State, Ctx): subTerm_nonTail(arg): ar => k(Arg(spread = S(true), ar) :: Nil) + def ref(ref: st.Ref, disamb: Opt[DefinitionSymbol[?]], inStmtPos: Bool)(k: Result => Block)(using Subst): Block = + def warnStmt = if inStmtPos then + raise: + WarningReport(msg"Pure expression in statement position" -> ref.toLoc :: Nil, S(ref)) + + val sym = ref.sym + sym match + case ctx.builtins.source.bms | ctx.builtins.js.bms | ctx.builtins.wasm.bms | ctx.builtins.debug.bms | ctx.builtins.annotations.bms => + return fail: + ErrorReport( + msg"Module '${sym.nme}' is virtual (i.e., \"compiler fiction\"); cannot be used directly" -> ref.toLoc :: + Nil, S(ref), source = Diagnostic.Source.Compilation) + case sym if sym.asCls.exists(ctx.builtins.virtualClasses) => + return fail: + ErrorReport( + msg"Symbol '${sym.nme}' is virtual (i.e., \"compiler fiction\"); cannot be used as a term" -> ref.toLoc :: + Nil, S(ref), source = Diagnostic.Source.Compilation) + case _ => () + + sym match + case sym: BuiltinSymbol => + warnStmt + if sym.binary then + val t1 = new Tree.Ident("arg1") + val t2 = new Tree.Ident("arg2") + val p1 = Param(FldFlags.empty, VarSymbol(t1), N, Modulefulness.none) + val p2 = Param(FldFlags.empty, VarSymbol(t2), N, Modulefulness.none) + val ps = PlainParamList(p1 :: p2 :: Nil) + val bod = st.App(ref, st.Tup(List(st.Ref(p1.sym)(t1, 666, N).resolve, st.Ref(p2.sym)(t2, 666, N).resolve)) + (Tree.Tup(Nil // FIXME should not be required (using dummy value) + )))( + Tree.App(Tree.Empty(), Tree.Empty()), // FIXME should not be required (using dummy value) + N, + FlowSymbol(sym.nme) + ).resolve + val (paramLists, bodyBlock) = setupFunctionDef(ps :: Nil, bod, S(sym.nme)) + tl.log(s"Ref builtin $sym") + assert(paramLists.length === 1) + return k(Lambda(paramLists.head, bodyBlock).withLocOf(ref)) + if sym.unary then + val t1 = new Tree.Ident("arg") + val p1 = Param(FldFlags.empty, VarSymbol(t1), N, Modulefulness.none) + val ps = PlainParamList(p1 :: Nil) + val bod = st.App(ref, st.Tup(List(st.Ref(p1.sym)(t1, 666, N).resolve)) + (Tree.Tup(Nil // FIXME should not be required (using dummy value) + )))( + Tree.App(Tree.Empty(), Tree.Empty()), // FIXME should not be required (using dummy value) + N, + FlowSymbol(sym.nme) + ).resolve + val (paramLists, bodyBlock) = setupFunctionDef(ps :: Nil, bod, S(sym.nme)) + tl.log(s"Ref builtin $sym") + assert(paramLists.length === 1) + return k(Lambda(paramLists.head, bodyBlock).withLocOf(ref)) + case bs: BlockMemberSymbol => + disamb.flatMap(_.defn) orElse bs.defn match + case S(_) if bs.asCls.exists(_ is ctx.builtins.Int31) => + return term(Sel(State.runtimeSymbol.ref().resolve, ref.tree)(S(bs), N).withLocOf(ref).resolve)(k) + case S(d) if d.hasDeclareModifier.isDefined => + return term(Sel(State.globalThisSymbol.ref().resolve, ref.tree)(S(bs), N).withLocOf(ref).resolve)(k) + case S(td: TermDefinition) if td.k is syntax.Fun => + // * Local functions with no parameter lists are getters + // * and are lowered to functions with an empty parameter list + // * (non-local functions are compiled into getter methods selected on some prefix) + if td.params.isEmpty then + val l = new TempSymbol(S(ref)) + return Assign(l, Call(Value.Ref(bs, disamb).withLocOf(ref), Nil)(true, true), k(Value.Ref(l, disamb))) + case S(_) => () + case N => () // TODO panic here; can only lower refs to elab'd symbols + case _ => () + warnStmt + k(subst(Value.Ref(sym, disamb).withLocOf(ref))) + @tailrec final def term(t: st, inStmtPos: Bool = false)(k: Result => Block)(using Subst): Block = tl.log(s"Lowering.term ${t.showDbg.truncate(100, "[...]")}${ @@ -341,73 +414,10 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case st.CtxTup(fs) => // * This case is currently triggered for code such as `f(using 42)` args(fs)(args => k(Tuple(mut = false, args))) - case ref @ st.Ref(sym) => - sym match - case ctx.builtins.source.bms | ctx.builtins.js.bms | ctx.builtins.wasm.bms | ctx.builtins.debug.bms | ctx.builtins.annotations.bms => - return fail: - ErrorReport( - msg"Module '${sym.nme}' is virtual (i.e., \"compiler fiction\"); cannot be used directly" -> t.toLoc :: - Nil, S(t), source = Diagnostic.Source.Compilation) - case sym if sym.asCls.exists(ctx.builtins.virtualClasses) => - return fail: - ErrorReport( - msg"Symbol '${sym.nme}' is virtual (i.e., \"compiler fiction\"); cannot be used as a term" -> t.toLoc :: - Nil, S(t), source = Diagnostic.Source.Compilation) - case _ => () - - sym match - case sym: BuiltinSymbol => - warnStmt - if sym.binary then - val t1 = new Tree.Ident("arg1") - val t2 = new Tree.Ident("arg2") - val p1 = Param(FldFlags.empty, VarSymbol(t1), N, Modulefulness.none) - val p2 = Param(FldFlags.empty, VarSymbol(t2), N, Modulefulness.none) - val ps = PlainParamList(p1 :: p2 :: Nil) - val bod = st.App(t, st.Tup(List(st.Ref(p1.sym)(t1, 666, N).resolve, st.Ref(p2.sym)(t2, 666, N).resolve)) - (Tree.Tup(Nil // FIXME should not be required (using dummy value) - )))( - Tree.App(Tree.Empty(), Tree.Empty()), // FIXME should not be required (using dummy value) - N, - FlowSymbol(sym.nme) - ).resolve - val (paramLists, bodyBlock) = setupFunctionDef(ps :: Nil, bod, S(sym.nme)) - tl.log(s"Ref builtin $sym") - assert(paramLists.length === 1) - return k(Lambda(paramLists.head, bodyBlock).withLocOf(ref)) - if sym.unary then - val t1 = new Tree.Ident("arg") - val p1 = Param(FldFlags.empty, VarSymbol(t1), N, Modulefulness.none) - val ps = PlainParamList(p1 :: Nil) - val bod = st.App(t, st.Tup(List(st.Ref(p1.sym)(t1, 666, N).resolve)) - (Tree.Tup(Nil // FIXME should not be required (using dummy value) - )))( - Tree.App(Tree.Empty(), Tree.Empty()), // FIXME should not be required (using dummy value) - N, - FlowSymbol(sym.nme) - ).resolve - val (paramLists, bodyBlock) = setupFunctionDef(ps :: Nil, bod, S(sym.nme)) - tl.log(s"Ref builtin $sym") - assert(paramLists.length === 1) - return k(Lambda(paramLists.head, bodyBlock).withLocOf(ref)) - case bs: BlockMemberSymbol => - bs.defn match - case S(_) if bs.asCls.exists(_ is ctx.builtins.Int31) => - return term(Sel(State.runtimeSymbol.ref().resolve, ref.tree)(S(bs), N).withLocOf(ref).resolve)(k) - case S(d) if d.hasDeclareModifier.isDefined => - return term(Sel(State.globalThisSymbol.ref().resolve, ref.tree)(S(bs), N).withLocOf(ref).resolve)(k) - case S(td: TermDefinition) if td.k is syntax.Fun => - // * Local functions with no parameter lists are getters - // * and are lowered to functions with an empty parameter list - // * (non-local functions are compiled into getter methods selected on some prefix) - if td.params.isEmpty then - val l = new TempSymbol(S(t)) - return Assign(l, Call(Value.Ref(bs).withLocOf(ref), Nil)(true, true), k(Value.Ref(l))) - case S(_) => () - case N => () // TODO panic here; can only lower refs to elab'd symbols - case _ => () - warnStmt - k(subst(Value.Ref(sym).withLocOf(ref))) + case t @ st.Ref(sym) => + ref(t, N, inStmtPos)(k) + case st.Resolved(t @ st.Ref(bsym), sym) => + ref(t, S(sym), inStmtPos)(k) case st.App(ref @ Ref(sym: BuiltinSymbol), arg) => arg match case st.Tup(Nil) => @@ -438,7 +448,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): lamDef, k(Call( Value.Ref(State.runtimeSymbol).selN(Tree.Ident(if isAnd then "short_and" else "short_or")), - Arg(N, ar1) :: Arg(N, Value.Ref(lamSym)) :: Nil + Arg(N, ar1) :: Arg(N, Value.Ref(lamSym, N)) :: Nil )(true, false))) else subTerm_nonTail(arg2): ar2 => @@ -453,28 +463,33 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case _: sem.BuiltinSymbol => true case sym: sem.BlockMemberSymbol => sym.trmImplTree.fold(sym.clsTree.isDefined)(_.k is syntax.Fun) + case sym: sem.TermSymbol => sym.k is syntax.Fun // Do not perform safety check on `MatchResult` and `MatchFailure`. case sym => (sym is State.matchResultClsSymbol) || (sym is State.matchFailureClsSymbol) def conclude(fr: Path) = lowerCall(fr, isMlsFun, arg, t.toLoc)(k) + + val instantiated = f.instantiated + val instantiatedResolvedBms = instantiated.resolvedSym.flatMap(_.asBlkMember) + // * We have to instantiate `f` again because, if `f` is a Sel, the `term` // * function is not called again with f. See below `Sel` and `SelProj` cases. - f.instantiated match - case t if t.resolvedSym.exists(_ is ctx.builtins.js.bitand) => + instantiated match + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.js.bitand) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("bitand"))) - case t if t.resolvedSym.exists(_ is ctx.builtins.js.bitnot) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.js.bitnot) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("bitnot"))) - case t if t.resolvedSym.exists(_ is ctx.builtins.js.bitor) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.js.bitor) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("bitor"))) - case t if t.resolvedSym.exists(_ is ctx.builtins.js.shl) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.js.shl) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("shl"))) - case t if t.resolvedSym.isDefined && (t.resolvedSym.get is ctx.builtins.js.try_catch) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.js.try_catch) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("try_catch"))) - case t if t.resolvedSym.exists(_ is ctx.builtins.wasm.plus_impl) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.wasm.plus_impl) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("plus_impl"))) - case t if t.resolvedSym.exists(_ is ctx.builtins.Int31) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.Int31) => conclude(Value.Ref(State.runtimeSymbol).selN(Tree.Ident("Int31"))) - case t if t.resolvedSym.isDefined && (t.resolvedSym.get is ctx.builtins.debug.printStack) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.debug.printStack) => if !config.effectHandlers.exists(_.debug) then return fail: ErrorReport( @@ -482,22 +497,28 @@ class Lowering()(using Config, TL, Raise, State, Ctx): t.toLoc :: Nil, source = Diagnostic.Source.Compilation) conclude(Value.Ref(State.runtimeSymbol).selSN("raisePrintStackEffect").withLocOf(f)) - case t if t.resolvedSym.isDefined && (t.resolvedSym.get is ctx.builtins.debug.getLocals) => + case t if instantiatedResolvedBms.exists(_ is ctx.builtins.debug.getLocals) => if !config.effectHandlers.exists(_.debug) then return fail: ErrorReport( msg"Debugging functions are not enabled" -> t.toLoc :: Nil, source = Diagnostic.Source.Compilation) - conclude(Value.Ref(ctx.builtins.debug.getLocals).withLocOf(f)) + conclude(Value.Ref(ctx.builtins.debug.getLocals, N).withLocOf(f)) // * Due to whacky JS semantics, we need to make sure that selections leading to a call // * are preserved in the call and not moved to a temporary variable. case sel @ Sel(prefix, nme) => subTerm(prefix): p => - conclude(Select(p, nme)(sel.sym).withLocOf(sel)) + conclude(Select(p, nme)(N).withLocOf(sel)) + case Resolved(sel @ Sel(prefix, nme), sym) => + subTerm(prefix): p => + conclude(Select(p, nme)(S(sym)).withLocOf(sel)) case sel @ SelProj(prefix, _, nme) => subTerm(prefix): p => - conclude(Select(p, nme)(sel.sym).withLocOf(sel)) + conclude(Select(p, nme)(N).withLocOf(sel)) + case Resolved(sel @ SelProj(prefix, _, nme), sym) => + subTerm(prefix): p => + conclude(Select(p, nme)(S(sym)).withLocOf(sel)) case _ => subTerm(f)(conclude) case h @ Handle(lhs, rhs, as, cls, defs, bod) => if !lowerHandlers then @@ -555,7 +576,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val lamDef = FunDefn(N, lamSym, paramLists, bodyBlock) Define( lamDef, - k(lamSym |> Value.Ref.apply)) + k(Value.Ref(lamSym, N))) /* case t @ st.If(Split.Let(sym, trm, tail)) => @@ -696,13 +717,19 @@ class Lowering()(using Config, TL, Raise, State, Ctx): ) case sel @ Sel(prefix, nme) => - setupSelection(prefix, nme, sel.sym)(k) - + setupSelection(prefix, nme, N)(k) + case Resolved(sel @ Sel(prefix, nme), sym) => + setupSelection(prefix, nme, S(sym))(k) + case sel @ SynthSel(prefix, nme) => // * Not using `setupSelection` as these selections are not meant to be sanity-checked subTerm(prefix): p => - k(Select(p, nme)(sel.sym)) - + k(Select(p, nme)(N)) + case Resolved(sel @ SynthSel(prefix, nme), sym) => + // * Not using `setupSelection` as these selections are not meant to be sanity-checked + subTerm(prefix): p => + k(Select(p, nme)(S(sym))) + case DynSel(prefix, fld, ai) => subTerm(prefix): p => subTerm_nonTail(fld): f => @@ -738,7 +765,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): val pctor = parentConstructor(cls, as) val clsDef = ClsLikeDefn(N, isym, sym, syntax.Cls, N, Nil, S(sr), mtds, privateFlds, publicFlds, pctor, ctor, N, N) - val inner = new New(sym.ref().resolve, Nil, N) + val inner = new New(sym.ref().resolved(isym), Nil, N)(N) Define(clsDef, term_nonTail(if mut then Mut(inner) else inner)(k)) case Try(sub, finallyDo) => @@ -753,7 +780,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx): // * BbML-specific cases: t.Cls#field and mutable operations case sp @ SelProj(prefix, _, proj) => - setupSelection(prefix, proj, sp.sym)(k) + setupSelection(prefix, proj, N)(k) + case Resolved(sp @ SelProj(prefix, _, proj), sym) => + setupSelection(prefix, proj, S(sym))(k) case Region(reg, body) => Assign(reg, Instantiate(mut = false, Select(Value.Ref(State.globalThisSymbol), Tree.Ident("Region"))(N), Nil), term_nonTail(body)(k)) @@ -851,8 +880,10 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case Ref(sym) if Elaborator.binaryOps.contains(sym.nme) => // builtin symbols val l = new TempSymbol(N) setupTerm("Builtin", Value.Lit(Tree.StrLit(sym.nme)) :: Nil)(k) + case Resolved(Ref(sym), disamb) => + k(Value.Ref(sym, S(disamb))) case Ref(sym) => - k(Value.Ref(sym)) + k(Value.Ref(sym, N)) case SynthSel(Ref(sym: ModuleOrObjectSymbol), name) => // Local cross-stage references setupSymbol(sym): r1 => val l1, l2 = new TempSymbol(N) @@ -1037,7 +1068,7 @@ class Lowering()(using Config, TL, Raise, State, Ctx): case Lambda(params, body) => val lamSym = BlockMemberSymbol("lambda", Nil, false) val lamDef = FunDefn(N, lamSym, params :: Nil, body) - Define(lamDef, k(lamSym |> Value.Ref.apply)) + Define(lamDef, k(Value.Ref(lamSym, N))) case r => val l = new TempSymbol(N) Assign(l, r, k(l |> Value.Ref.apply)) @@ -1076,10 +1107,9 @@ class Lowering()(using Config, TL, Raise, State, Ctx): ) - def setupSelection(prefix: Term, nme: Tree.Ident, sym: Opt[FieldSymbol])(k: Result => Block)(using Subst): Block = + def setupSelection(prefix: Term, nme: Tree.Ident, disamb: Opt[DefinitionSymbol[?]])(k: Result => Block)(using Subst): Block = subTerm(prefix): p => - val selRes = TempSymbol(N, "selRes") - k(Select(p, nme)(sym)) + k(Select(p, nme)(disamb)) final def setupFunctionOrByNameDef(paramLists: List[ParamList], bodyTerm: Term, name: Option[Str]) (using Subst): (List[ParamList], Block) = @@ -1104,16 +1134,16 @@ trait LoweringSelSanityChecks(using Config, TL, Raise, State) private val instrument: Bool = config.sanityChecks.isDefined - override def setupSelection(prefix: st, nme: Tree.Ident, sym: Opt[FieldSymbol])(k: Result => Block)(using Subst): Block = - if !instrument then return super.setupSelection(prefix, nme, sym)(k) + override def setupSelection(prefix: st, nme: Tree.Ident, disamb: Opt[DefinitionSymbol[?]])(k: Result => Block)(using Subst): Block = + if !instrument then return super.setupSelection(prefix, nme, disamb)(k) subTerm(prefix): p => val selRes = TempSymbol(N, "selRes") // * We are careful to access `x.f` before `x.f$__checkNotMethod` in case `x` is, eg, `undefined` and // * the access should throw an error like `TypeError: Cannot read property 'f' of undefined`. val b0 = blockBuilder - .assign(selRes, Select(p, nme)(sym)) - (if sym.isDefined then - // * If the symbol is known, the elaborator will have already checked the access [invariant:1] + .assign(selRes, Select(p, nme)(disamb)) + (if disamb.isDefined then + // * If the symbol is known, the resolver will have already checked the access [invariant:1] b0 else b0 .assign(TempSymbol(N, "discarded"), Select(p, Tree.Ident(nme.name+"$__checkNotMethod"))(N))) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index f0994b6b16..f4596aab61 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -91,7 +91,7 @@ object Printer: else doc def mkDocument(value: Value)(using Raise, Scope): Document = value match - case Value.Ref(l) => getVar(l) + case Value.Ref(l, _) => getVar(l) case Value.This(sym) => doc"this" case Value.Lit(lit) => doc"${lit.idStr}" diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/StackSafeTransform.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/StackSafeTransform.scala index ffd0e86111..df9f4130eb 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/StackSafeTransform.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/StackSafeTransform.scala @@ -14,7 +14,7 @@ class StackSafeTransform(depthLimit: Int, paths: HandlerPaths, doUnwindMap: Map[ val doUnwindFns = doUnwindMap.values.collect: case s: Select if s.symbol.isDefined => s.symbol.get - case Value.Ref(sym) => sym + case Value.Ref(sym, _) => sym .toSet private val runtimePath: Path = State.runtimeSymbol.asPath @@ -50,7 +50,7 @@ class StackSafeTransform(depthLimit: Int, paths: HandlerPaths, doUnwindMap: Map[ // Rewrites anything that can contain a Call to increase the stack depth def transform(b: Block, curDepth: => Symbol, isTopLevel: Bool = false): Block = def usesStack(r: Result) = r match - case Call(Value.Ref(_: BuiltinSymbol), _) => false + case Call(Value.Ref(_: BuiltinSymbol, _), _) => false case c: Call if !c.mayRaiseEffects => false // a call can only trigger a stack delay if it can raise effects case _: Call | _: Instantiate => true case _ => false @@ -98,7 +98,7 @@ class StackSafeTransform(depthLimit: Int, paths: HandlerPaths, doUnwindMap: Map[ new BlockTraverserShallow: applyBlock(b) override def applyResult(r: Result): Unit = r match - case Call(Value.Ref(_: BuiltinSymbol), _) => () + case Call(Value.Ref(_: BuiltinSymbol, _), _) => () case _: Call | _: Instantiate => trivial = false case _ => () trivial @@ -166,7 +166,7 @@ class StackSafeTransform(depthLimit: Int, paths: HandlerPaths, doUnwindMap: Map[ // However, due to how tightly coupled the stack safety and handler lowering are, it might be // better to simply merge the two passes in the future. val (blk, defns) = doUnwindPath.get match - case Value.Ref(sym) => rewritten.floatOutDefns() + case Value.Ref(sym, _) => rewritten.floatOutDefns() case _ => (rewritten, Nil) defns.foldLeft(blk)((acc, defn) => Define(defn, acc)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/UsedVarAnalyzer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/UsedVarAnalyzer.scala index a9b775047c..99d30d9cab 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/UsedVarAnalyzer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/UsedVarAnalyzer.scala @@ -144,10 +144,10 @@ class UsedVarAnalyzer(b: Block, handlerPaths: Opt[HandlerPaths])(using State): case _ => super.applyBlock(b) override def applyValue(v: Value): Unit = v match - case Value.Ref(_: BuiltinSymbol) => super.applyValue(v) - case RefOfBms(l) => + case Value.Ref(_: BuiltinSymbol, _) => super.applyValue(v) + case RefOfBms(l, _) => accessed = accessed.addRefdDefn(l) - case Value.Ref(l) => + case Value.Ref(l, _) => accessed = accessed.addAccess(l) case _ => super.applyValue(v) @@ -363,7 +363,7 @@ class UsedVarAnalyzer(b: Block, handlerPaths: Opt[HandlerPaths])(using State): hasMutator += l override def applyResult(r: Result): Unit = r match - case Call(RefOfBms(l), args) => + case Call(RefOfBms(l, _), args) => args.map(super.applyArg(_)) handleCalledBms(l) case Instantiate(mut, InstSel(l), args) => @@ -372,7 +372,7 @@ class UsedVarAnalyzer(b: Block, handlerPaths: Opt[HandlerPaths])(using State): case _ => super.applyResult(r) override def applyPath(p: Path): Unit = p match - case RefOfBms(l) => + case RefOfBms(l, _) => defnSyms.get(l) match case None => super.applyPath(p) case Some(defn) => @@ -402,7 +402,7 @@ class UsedVarAnalyzer(b: Block, handlerPaths: Opt[HandlerPaths])(using State): reqCapture += l hasMutator += l - case Value.Ref(l) => + case Value.Ref(l, _) => if hasMutator.contains(l) then reqCapture += (l) case _ => super.applyPath(p) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala index cf02ddcddf..47fbd2f841 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/js/JSBuilder.scala @@ -108,22 +108,25 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: case Value.This(sym) => scope.findThis_!(sym) case Value.Lit(Tree.StrLit(value)) => makeStringLiteral(value) case Value.Lit(lit) => lit.idStr - case Value.Ref(l: BuiltinSymbol) => + case Value.Ref(l: BuiltinSymbol, _) => if l.nullary then l.nme else errExpr(msg"Illegal reference to builtin symbol '${l.nme}'") - case Value.Ref(l) => getVar(l, r.toLoc) - - case Call(Value.Ref(l: BuiltinSymbol), lhs :: rhs :: Nil) if !l.functionLike => + case Value.Ref(l, disamb) => l match + case l: BlockMemberSymbol if disamb.exists(_.shouldBeLifted) => + doc"${getVar(l, l.toLoc)}.class" + case _ => + getVar(l, r.toLoc) + case Call(Value.Ref(l: BuiltinSymbol, _), lhs :: rhs :: Nil) if !l.functionLike => if l.binary then val res = doc"${operand(lhs)} ${l.nme} ${operand(rhs)}" if needsParens(l.nme) then doc"(${res})" else res else errExpr(msg"Cannot call non-binary builtin symbol '${l.nme}'") - case Call(Value.Ref(l: BuiltinSymbol), rhs :: Nil) if !l.functionLike => + case Call(Value.Ref(l: BuiltinSymbol, _), rhs :: Nil) if !l.functionLike => if l.unary then val res = doc"${l.nme} ${operand(rhs)}" if needsParens(l.nme) then doc"(${res})" else res else errExpr(msg"Cannot call non-unary builtin symbol '${l.nme}'") - case Call(Value.Ref(l: BuiltinSymbol), args) => + case Call(Value.Ref(l: BuiltinSymbol, _), args) => if l.functionLike then val argsDoc = args.map(argument).mkDocument(", ") doc"${l.nme}(${argsDoc})" @@ -146,7 +149,10 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: case Lambda(ps, bod) => scope.nest givenIn: val (params, bodyDoc) = setupFunction(none, ps, bod) doc"($params) => ${ braced(bodyDoc) }" - case Select(qual, id) => + case s @ Select(qual, id) => + val dotClass = s.symbol match + case S(ds) if ds.shouldBeLifted => doc".class" + case _ => doc"" val name = id.name doc"${result(qual)}${ if isValidFieldName(name) @@ -154,7 +160,7 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: else name.toIntOption match case S(index) => doc"[$index]" case N => doc"[${makeStringLiteral(name)}]" - }" + }${dotClass}" case DynSelect(qual, fld, ai) => if ai then doc"${result(qual)}.at(${result(fld)})" @@ -335,7 +341,7 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: else v ownr match case S(owner) => - doc" # ${result(Value.Ref(owner))}.${sym.nme}$extraPath = $rhs" + doc" # ${result(Value.Ref(owner, N))}.${sym.nme}$extraPath = $rhs" case N => doc" # ${getVar(sym, sym.toLoc)}$extraPath = $rhs" } :/: ctorHead :: " " :: braced(ctorAux) @@ -456,6 +462,7 @@ class JSBuilder(using TL, State, Ctx) extends CodeBuilder: case Elaborator.ctx.builtins.BigInt => doc"typeof $sd === 'bigint'" case Elaborator.ctx.builtins.Symbol.module => doc"typeof $sd === 'symbol'" case Elaborator.ctx.builtins.TypedArray => doc"globalThis.ArrayBuffer.isView($sd) && !($sd instanceof globalThis.DataView)" + case _: ModuleOrObjectSymbol => doc"$sd instanceof ${result(pth)}.class" case _ => doc"$sd instanceof ${result(pth)}" case Case.Tup(len, inf) => doc"$runtimeVar.Tuple.isArrayLike($sd) && $sd.length ${if inf then ">=" else "==="} ${len}" case Case.Field(name = n, safe = false) => @@ -702,7 +709,16 @@ object JSBuilder: then c.toString else f"\\u${c.toInt}%04X" }.mkString - + + extension (dsym: DefinitionSymbol[?]) + def shouldBeLifted: Bool = + val bsym = dsym.asBlkMember + ( + (dsym.asTrm orElse bsym.flatMap(_.asTrm)).isDefined || + (dsym.asCls orElse bsym.flatMap(_.asCls)).flatMap(_.defn).exists(_.paramsOpt.isDefined) + ) && + (dsym.asModOrObj orElse dsym.asCls).isDefined + end JSBuilder diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 0a5fa879ce..f287cedb41 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -31,7 +31,7 @@ final case class BuiltinSymbols( var builtinSym: Opt[Local] = None, fieldSym: MutMap[Int, VarSymbol] = MutMap.empty, applySym: MutMap[Int, BlockMemberSymbol] = MutMap.empty, - tupleSym: MutMap[Int, MemberSymbol[? <: ClassLikeDef]] = MutMap.empty, + tupleSym: MutMap[Int, DefinitionSymbol[? <: ClassLikeDef]] = MutMap.empty, runtimeSym: Opt[TempSymbol] = None, ): def hiddenClasses = callableSym.toSet @@ -41,28 +41,28 @@ final case class Ctx( class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Local, Local] = Map.empty, fn_ctx: Map[Local, FuncInfo] = Map.empty, // is a known function - class_ctx: Map[MemberSymbol[? <: ClassLikeDef], ClassInfo] = Map.empty, - class_sym_ctx: Map[BlockMemberSymbol, MemberSymbol[? <: ClassLikeDef]] = Map.empty, + class_ctx: Map[DefinitionSymbol[? <: ClassLikeDef], ClassInfo] = Map.empty, + class_sym_ctx: Map[BlockMemberSymbol, DefinitionSymbol[? <: ClassLikeDef]] = Map.empty, flow_ctx: Map[Path, Local] = Map.empty, isTopLevel: Bool = true, - method_class: Opt[MemberSymbol[? <: ClassLikeDef]] = None, + method_class: Opt[DefinitionSymbol[? <: ClassLikeDef]] = None, builtinSym: BuiltinSymbols = BuiltinSymbols() ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match case None => bErrStop(msg"Function name not found: ${n.toString()}") case Some(value) => value - def addClassInfo(n: MemberSymbol[? <: ClassLikeDef], bsym: BlockMemberSymbol, m: ClassInfo) = + def addClassInfo(n: DefinitionSymbol[? <: ClassLikeDef], bsym: BlockMemberSymbol, m: ClassInfo) = copy(class_ctx = class_ctx + (n -> m), class_sym_ctx = class_sym_ctx + (bsym -> n)) def addName(n: Local, m: Local) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Local)(using Raise) = symbol_ctx.get(n) match case None => bErrStop(msg"Name not found: ${n.toString}") case Some(value) => value - def findClassInfo(n: MemberSymbol[? <: ClassLikeDef])(using Raise) = class_ctx.get(n) match + def findClassInfo(n: DefinitionSymbol[? <: ClassLikeDef])(using Raise) = class_ctx.get(n) match case None => bErrStop(msg"Class not found: ${n.toString}") case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) - def setClass(c: MemberSymbol[? <: ClassLikeDef]) = copy(method_class = Some(c)) + def setClass(c: DefinitionSymbol[? <: ClassLikeDef]) = copy(method_class = Some(c)) def nonTopLevel = copy(isTopLevel = false) object Ctx: @@ -222,8 +222,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): given Ctx = ctx.setClass(isym) val funcs = methods.map(bMethodDef) def parentFromPath(p: Path): Ls[Local] = p match - case Value.Ref(l) => fromMemToClass(l) :: Nil - case Select(Value.Ref(l), Tree.Ident("class")) => fromMemToClass(l) :: Nil + case Value.Ref(l, _) => fromMemToClass(l) :: Nil + case Select(Value.Ref(l, _), Tree.Ident("class")) => fromMemToClass(l) :: Nil case _ => bErrStop(msg"Unsupported parent path ${p.toString()}") ClassInfo( uid.make, @@ -277,12 +277,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): v match - case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => + case Value.Ref(l: TermSymbol, _) if l.owner.nonEmpty => k(l |> sr) - case Value.Ref(sym) if sym.nme.isCapitalized => + case Value.Ref(sym, _) if sym.nme.isCapitalized => val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), Ls()), k(v |> sr)) - case Value.Ref(l) => + case Value.Ref(l, _) => ctx.fn_ctx.get(l) match case Some(f) => val tempSymbols = (0 until f.paramsSize).map(x => newNamed("arg")) @@ -297,7 +297,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Value.Lit(lit) => k(Expr.Literal(lit)) - private def getClassOfField(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = + private def getClassOfField(p: DefinitionSymbol[?])(using ctx: Ctx)(using Raise, Scope): Local = trace[Local](s"bClassOfField { $p } begin", x => s"bClassOfField end: $x"): p match case ts: TermSymbol => ts.owner.get @@ -308,8 +308,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Some(value) => bErrStop(msg"Member symbol without class definition ${value.toString}") case None => bErrStop(msg"Member symbol without definition ${ms.toString}") - private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): MemberSymbol[? <: ClassLikeDef] = - trace[MemberSymbol[? <: ClassLikeDef]](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): + private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): DefinitionSymbol[? <: ClassLikeDef] = + trace[DefinitionSymbol[? <: ClassLikeDef]](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): m match case ms: MemberSymbol[?] => ms.defn match @@ -322,9 +322,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match - case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtinSym.runtimeSym.get => + case s @ Select(Value.Ref(sym, _), Tree.Ident("Unit")) if sym is ctx.builtinSym.runtimeSym.get => bPath(Value.Lit(Tree.UnitLit(false)))(k) - case s @ Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => + case s @ Select(Value.Ref(cls: ClassSymbol, _), name) if ctx.method_class.contains(cls) => s.symbol match case None => ctx.flow_ctx.get(p) match @@ -366,12 +366,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bResult begin", x => s"bResult end: ${x.show}"): r match - case Call(Value.Ref(sym: BuiltinSymbol), args) => + case Call(Value.Ref(sym: BuiltinSymbol, _), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetExpr(v, Expr.BasicOp(sym, args), k(v |> sr)) - case Call(Value.Ref(sym: MemberSymbol[?]), args) if sym.defn.exists(defn => defn match + case Call(Value.Ref(sym: MemberSymbol[?], _), args) if sym.defn.exists(defn => defn match case cls: ClassLikeDef => true case _ => false ) => @@ -380,7 +380,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) - case Call(s @ Value.Ref(sym), args) => + case Call(s @ Value.Ref(sym, _), args) => val v: Local = newTemp ctx.fn_ctx.get(sym) match case Some(f) => @@ -393,22 +393,22 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bArgs(args): case args: Ls[TrivialExpr] => Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) - case Call(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("builtin")), args) => + case Call(Select(Value.Ref(_: TopLevelSymbol, _), Tree.Ident("builtin")), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetCall(Ls(v), builtin, args, k(v |> sr)) - case Call(Select(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("console")), Tree.Ident("log")), args) => + case Call(Select(Select(Value.Ref(_: TopLevelSymbol, _), Tree.Ident("console")), Tree.Ident("log")), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetCall(Ls(v), builtin, Expr.Literal(Tree.StrLit("println")) :: args, k(v |> sr)) - case Call(Select(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("Math")), Tree.Ident(mathPrimitive)), args) => + case Call(Select(Select(Value.Ref(_: TopLevelSymbol, _), Tree.Ident("Math")), Tree.Ident(mathPrimitive)), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetCall(Ls(v), builtin, Expr.Literal(Tree.StrLit(mathPrimitive)) :: args, k(v |> sr)) - case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => + case Call(s @ Select(r @ Value.Ref(sym, _), Tree.Ident(fld)), args) if s.symbol.isDefined => bPath(r): case r => bArgs(args): @@ -419,7 +419,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Call(_, _) => bErrStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( false, - Select(Value.Ref(sym), Tree.Ident("class")), args) => + Value.Ref(sym, S(_: (ClassSymbol | ModuleOrObjectSymbol))), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp @@ -474,7 +474,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) - case Throw(Instantiate(false, Select(Value.Ref(_), ident), + case Throw(Instantiate(false, Select(Value.Ref(_, _), ident), Ls(Arg(N, Value.Lit(Tree.StrLit(e)))))) if ident.name === "Error" => Node.Panic(e) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 6c41a73333..69a5dd7b66 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -38,7 +38,7 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, - symbol: MemberSymbol[? <: ClassLikeDef], + symbol: DefinitionSymbol[? <: ClassLikeDef], fields: Ls[VarSymbol], parents: Ls[Local], methods: Map[Local, Func], @@ -82,7 +82,7 @@ sealed trait TrivialExpr: enum Expr: case Ref(sym: Local) extends Expr, TrivialExpr case Literal(lit: hkmc2.syntax.Literal) extends Expr, TrivialExpr - case CtorApp(cls: MemberSymbol[? <: ClassLikeDef], args: Ls[TrivialExpr]) + case CtorApp(cls: DefinitionSymbol[? <: ClassLikeDef], args: Ls[TrivialExpr]) case Select(name: Local, cls: Local, field: Str) case BasicOp(name: BuiltinSymbol, args: Ls[TrivialExpr]) case AssignField(assignee: Local, cls: Local, field: Str, value: TrivialExpr) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/Wasm.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/Wasm.scala index c94100de54..cad44a8592 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/Wasm.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/Wasm.scala @@ -5,7 +5,7 @@ package text import mlscript.utils.*, shorthands.* import document.* -import semantics.FieldSymbol +import semantics.DefinitionSymbol import scala.collection.Map @@ -124,7 +124,7 @@ case class Field( })" /** A type representing a structure type. */ -case class StructType(fields: Map[FieldSymbol, NumIdx -> Field]) extends ToWat: +case class StructType(fields: Map[DefinitionSymbol[?], NumIdx -> Field]) extends ToWat: def fieldSeq: Seq[Field] = fields.values.toSeq.sortBy(_._1.index).map(_._2) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/WatBuilder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/WatBuilder.scala index 967bbee669..8abdef10f8 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/WatBuilder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/wasm/text/WatBuilder.scala @@ -115,7 +115,7 @@ class WatBuilder(using TraceLogger, State) extends CodeBuilder: ) case r => result(r) - def fieldSelect(thisSym: BlockMemberSymbol, sym: FieldSymbol)(using Ctx, Raise): FieldIdx = + def fieldSelect(thisSym: BlockMemberSymbol, sym: DefinitionSymbol[?])(using Ctx, Raise): FieldIdx = val structInfo = ctx.getTypeInfo_!(thisSym) val symToField = structInfo.compType match case ty: StructType => ty.fields @@ -150,13 +150,13 @@ class WatBuilder(using TraceLogger, State) extends CodeBuilder: ref.i31(i32.const(if value then 1 else 0)) case Value.Lit(IntLit(value)) => ref.i31(i32.const(value.toInt)) - case Value.Ref(l) => + case Value.Ref(l, _) => ctx.getFunc(l) match case S(funcIdx) => ref.func(funcIdx, RefType(ctx.getFuncInfo_!(l).typeIdx, nullable = false)) case N => getVar(l, r.toLoc) - case Call(Value.Ref(l: BuiltinSymbol), lhs :: rhs :: Nil) if !l.functionLike => + case Call(Value.Ref(l: BuiltinSymbol, _), lhs :: rhs :: Nil) if !l.functionLike => if l.binary then l.nme match case "+" => @@ -252,15 +252,16 @@ class WatBuilder(using TraceLogger, State) extends CodeBuilder: ) case Instantiate(_, cls, as) => - val ctorClsPath = cls match - case sel: Select => sel + val ctorClsSymOpt = cls match + case ref: Value.Ref => ref.disamb + case sel: Select => sel.symbol case cls => return errExpr( Ls( - msg"WatBuilder::result for Instantiate(...) where `cls` is not a Select(...) path not implemented yet " -> cls.toLoc + msg"WatBuilder::result for Instantiate(...) where `cls` is not a Ref(...) or Select(...) path not implemented yet " -> cls.toLoc ), extraInfo = S(s"Block IR of `cls` expression: ${cls.toString}") ) - val ctorClsSym = ctorClsPath.symbol match + val ctorClsSym = ctorClsSymOpt match case S(sym) => sym case N => return errExpr( Ls( diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala index 2982c96c8c..5470af11a2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala @@ -194,19 +194,19 @@ object Elaborator: object Ctx: abstract class Elem: def nme: Str - def ref(id: Ident)(using Elaborator.State): Term + def ref(id: Ident)(using Elaborator.State): Resolvable def symbol: Opt[Symbol] def isImport: Bool final case class RefElem(sym: Symbol) extends Elem: val nme = sym.nme - def ref(id: Ident)(using Elaborator.State): Term = + def ref(id: Ident)(using Elaborator.State): Resolvable = // * Note: due to symbolic ops, we may have `id.name =/= nme`; // * e.g., we can have `id.name = "|>"` and `nme = "pipe"`. Term.Ref(sym)(id, 666, N) // FIXME: 666 is a temporary placeholder def symbol = S(sym) def isImport: Bool = false final case class SelElem(base: Elem, nme: Str, symOpt: Opt[FieldSymbol], isImport: Bool) extends Elem: - def ref(id: Ident)(using Elaborator.State): Term = + def ref(id: Ident)(using Elaborator.State): Resolvable = // * Same remark as in RefElem#ref Term.SynthSel(base.ref(Ident(base.nme)), new Ident(nme).withLocOf(id))(symOpt, N) @@ -245,10 +245,11 @@ object Elaborator: val nonLocalRet = val id = new Ident("ret") BlockMemberSymbol(id.name, Nil, true) - val matchResultClsSymbol = + val (matchResultClsSymbol, matchResultTrmSymbol) = val id = new Ident("MatchResult") val td = TypeDef(syntax.Cls, App(id, Tup(Ident("output") :: Ident("bindings") :: Nil)), N) val cs = ClassSymbol(td, id) + val ts = TermSymbol(syntax.Fun, N, id) val flag = FldFlags.empty.copy(isVal = true) val ps = PlainParamList( Param(flag, VarSymbol(Ident("output")), N, Modulefulness(N)(false)) :: @@ -256,16 +257,17 @@ object Elaborator: Nil) cs.defn = S(ClassDef.Parameterized(N, syntax.Cls, cs, BlockMemberSymbol(cs.name, Nil), Nil, ps, Nil, N, ObjBody(Blk(Nil, Term.Lit(UnitLit(false)))), N, Nil)) - cs - val matchFailureClsSymbol = + cs -> ts + val (matchFailureClsSymbol, matchFailureTrmSymbol) = val id = new Ident("MatchFailure") val td = DummyTypeDef(syntax.Cls) val cs = ClassSymbol(td, id) + val ts = TermSymbol(syntax.Fun, N, id) val flag = FldFlags.empty.copy(isVal = true) val ps = PlainParamList(Param(flag, VarSymbol(Ident("errors")), N, Modulefulness(N)(false)) :: Nil) cs.defn = S(ClassDef.Parameterized(N, syntax.Cls, cs, BlockMemberSymbol(cs.name, td :: Nil), Nil, ps, Nil, N, ObjBody(Blk(Nil, Term.Lit(UnitLit(false)))), N, Nil)) - cs + cs -> ts val builtinOpsMap = val baseBuiltins = builtins.map: op => op -> BuiltinSymbol(op, @@ -524,7 +526,7 @@ extends Importer: case _ => raise(ErrorReport(msg"Identifier `${idn.name}` does not name a known class symbol." -> idn.toLoc :: Nil)) N - Term.SelProj(subterm(pre), c, idp)(f) + Term.SelProj(subterm(pre), c, idp)(f, N) case App(Ident("#"), Tup(Sel(pre, Ident(name)) :: App(Ident(proj), args) :: Nil)) => subterm(App(App(Ident("#"), Tup(Sel(pre, Ident(name)) :: Ident(proj) :: Nil)), args)) case App(Ident("!"), Tup(rhs :: Nil)) => @@ -605,7 +607,7 @@ extends Importer: ) val rs = FlowSymbol.app() Term.Lam(ps, - Term.App(Term.SelProj(self.ref(), c, nme)(f), args.ref())( + Term.App(Term.SelProj(self.ref(), c, nme)(f, N), args.ref())( App(nme, Tup(Nil)) // FIXME , N, rs) ) @@ -642,11 +644,11 @@ extends Importer: subterm(c2), // * Note: we'll catch bad `new` targets during type checking args.map(subterm(_)), bodo - ).withLocOf(tree) + )(N).withLocOf(tree) if mut then Term.Mut(inner) else inner case N => Term.New(State.globalThisSymbol.ref().sel(Ident("Object"), S(ctx.builtins.Object)), - Nil, bodo).withLocOf(tree) + Nil, bodo)(N).withLocOf(tree) // case _ => // raise(ErrorReport(msg"Illegal new expression." -> tree.toLoc :: Nil)) @@ -1108,6 +1110,7 @@ extends Importer: Fun, mtdSym, tsym, PlainParamList(Param(FldFlags.empty, valueSym, N, Modulefulness.none) :: Nil) :: Nil, N, N, S(valueSym.ref(Ident("value"))), FlowSymbol(s"‹result of non-local return›"), TermDefFlags.empty, Modulefulness.none, Nil, N) tsym.defn = S(td) + mtdSym.tsym = S(tsym) val htd = HandlerTermDefinition(resumeSym, td) Term.Handle(nonLocalRetHandler, state.nonLocalRetHandlerTrm, Nil, clsSym, htd :: Nil, b) val r = FlowSymbol(s"‹result of ${sym}›") @@ -1123,9 +1126,10 @@ extends Importer: val tsym = TermSymbol(k, owner, id) // TODO? val tdf = TermDefinition(k, sym, tsym, pss, tps, s, body, r, - TermDefFlags.empty.copy(isMethod = isMethod), mfn, annotations, N) + TermDefFlags.empty.copy(isMethod = isMethod), mfn, annotations, N).withLocOf(td) tsym.defn = S(tdf) sym.defn = S(tdf) + sym.tsym = S(tsym) tdf go(sts, Nil, tdf :: acc) @@ -1208,10 +1212,11 @@ extends Importer: p.modulefulness, Nil, N, - ) + ).withLocOf(p) assert(p.fldSym.isEmpty) p.fldSym = S(fsym) fsym.defn = S(fdef) + fsym.tsym = S(tsym) tsym.defn = S(fdef) fdef :: Nil else @@ -1232,7 +1237,12 @@ extends Importer: val (blk, c) = fn(using ctxWithFields) val blkWithFields: Blk = blk.copy(stats = fields ::: blk.stats) - (blkWithFields, c) + ObjBody.extractMembers(blkWithFields) match + case R(_) => + (blkWithFields, c) + case L(errs) => + errs.foreach(raise) + (blk, c) def mkBody(using Ctx) = withFields: body match @@ -1334,6 +1344,27 @@ extends Importer: val (bod, c) = mkBody ClassDef(owner, Cls, clsSym, sym, tps, pss, newOf(td), ObjBody(bod), annotations, comp) clsSym.defn = S(cd) + if pss.nonEmpty then + val ctsym = TermSymbol(Fun, S(clsSym), clsSym.id) + val ctdef = + TermDefinition( + Fun, + sym, + ctsym, + pss, + S(tps.map(tp => Param(FldFlags.empty, tp.sym, N, Modulefulness.none))), + S(clsSym.ref()), + N, + FlowSymbol(s"‹constructor›"), + TermDefFlags.empty, + Modulefulness.none, + annotations.collect: + case a @ Annot.Modifier(Keyword.`declare`) => a + , + S(clsSym), + ) + ctsym.defn = S(ctdef) + sym.tsym = S(ctsym) cd sym.defn = S(defn) go(sts, Nil, defn :: acc) diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Resolver.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Resolver.scala index ea57cc40aa..65adaf4c8b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Resolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Resolver.scala @@ -12,6 +12,8 @@ import Elaborator.State import Resolvable.* import typing.Type +import semantics.ucs.FlatPattern + import Message.MessageContext import scala.annotation.tailrec @@ -129,6 +131,8 @@ object Resolver: case Module(reason: Opt[Message]) case NonModule(reason: Opt[Message]) case Class(reason: Opt[Message]) + case Selectable(reason: Opt[Message]) + case PatternConstructor(reason: Opt[Message]) case Any def message: Ls[Message -> Opt[Loc]] = this match @@ -266,7 +270,7 @@ class Resolver(tl: TraceLogger) traverseDefn(tdf) case t: Term => - traverse(t, expect = NonModule(N)) + traverse(t, expect = Any) ictx // Default Case. e.g., import statements, let bindings. @@ -275,25 +279,13 @@ class Resolver(tl: TraceLogger) ictx traverseStmts(rest)(using newICtx) - - - def expand2DotClass(t: Resolvable, expect: Expect.Module | Expect.Class) = t.resolvedSym match - case S(bsym: BlockMemberSymbol) if bsym.hasLiftedClass => - val sym = expect match - case _: Expect.Module => bsym.asMod - case _: Expect.Class => bsym.asCls - sym.foreach: sym => - if sym isnt ctx.builtins.Array then - t.expand(S(Term.SynthSel(t.duplicate, new Tree.Ident("class"))(S(sym), S(Type.Ref(sym, Nil))))) - case _ => - () /** * Traverse a term: traverse the sub-terms, resolve the term, and * check the modulefulness of the term. */ def traverse(t: Term, expect: Expect)(using ictx: ICtx): Unit = - trace(s"Traversing term: $t"): + trace(s"Traversing term: $t (expect = ${expect})"): t match case blk: Term.Blk => @@ -305,7 +297,13 @@ class Resolver(tl: TraceLogger) def split(s: Split): Unit = s match case Split.Cons(head, tail) => traverse(head.scrutinee, expect = NonModule(N)) - head.pattern.subTerms.foreach(traverse(_, expect = NonModule(N))) + head.pattern match + case FlatPattern.ClassLike(constructor = t) => + head.pattern.subTerms.foreach: + case `t` => traverse(t, expect = PatternConstructor(N)) + case other => traverse(other, expect = NonModule(N)) + case _ => + head.pattern.subTerms.foreach(traverse(_, expect = NonModule(N))) split(head.continuation) split(tail) case Split.Let(sym, term, tail) => @@ -321,19 +319,9 @@ class Resolver(tl: TraceLogger) args.foreach(traverse(_, expect = NonModule(N))) defs.foreach(d => traverseDefn(d.td)) traverse(body, expect = NonModule(N)) - - case Term.New(cls, args, rft) => - traverse(cls, expect = Class(S("The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation."))) - args.foreach(traverse(_, expect = NonModule(N))) - rft.foreach((sym, bdy) => traverseBlock(bdy.blk)) case t: Resolvable => resolve(t, prefer = expect, inAppPrefix = false, inTyPrefix = false, inCtxPrefix = false) - t.expanded match - case t: Resolvable => expect match - case expect: Expect.Class => expand2DotClass(t, expect = expect) - case _ => - case _ => case _ => t.subTerms.foreach(traverse(_, expect = NonModule(N))) @@ -431,6 +419,35 @@ class Resolver(tl: TraceLogger) traverseBlock(cld.body.blk)(using withCtxParams) + def traversePattern(p: Pattern): Unit = p match + case _: (Pattern.Wildcard | Pattern.Literal | Pattern.Range) => () + case Pattern.Constructor(target, patternArguments, arguments) => + traverse(target, expect = PatternConstructor(N)) + patternArguments.foreach(traversePattern(_)) + arguments.foreach(_.foreach(traversePattern(_))) + case Pattern.Composition(_, left, right) => + traversePattern(left) + traversePattern(right) + case Pattern.Negation(pattern) => + traversePattern(pattern) + case Pattern.Concatenation(left, right) => + traversePattern(left) + traversePattern(right) + case Pattern.Tuple(leading, spread, trailing) => + leading.foreach(traversePattern(_)) + spread.foreach(traversePattern(_)) + trailing.foreach(traversePattern(_)) + case Pattern.Record(fields) => + fields.map((id, p) => traversePattern(p)) + case Pattern.Chain(first, second) => + traversePattern(first) + traversePattern(second) + case Pattern.Alias(pattern, _) => + traversePattern(pattern) + case Pattern.Transform(pattern, transform) => + traversePattern(pattern) + traverse(transform, expect = NonModule(N)) + defn match // Case: instance definition. Add the instance to the context. @@ -456,10 +473,10 @@ class Resolver(tl: TraceLogger) case defn: ClassLikeDef => log(s"Resolving ${defn.kind.desc} definition $defn") - // For pattern definitions, we need to traverse through the pattern body. defn match case defn: PatternDef => - defn.pattern.subTerms.foreach(traverse(_, expect = NonModule(N))) + // For pattern definitions, we need to traverse through the pattern body. + traversePattern(defn.pattern) case _: ClassLikeDef => () traverseClassLikeDef(defn) @@ -499,21 +516,23 @@ class Resolver(tl: TraceLogger) */ def resolve(t: Resolvable, prefer: Expect, inAppPrefix: Bool, inCtxPrefix: Bool, inTyPrefix: Bool)(using ICtx): (Opt[CallableDefinition], ICtx) = trace[(Opt[CallableDefinition], ICtx)]( - s"Resolving resolvable term: ${t}, (inPrefix = ${inTyPrefix})", + s"Resolving resolvable term: ${t}, (prefer = ${prefer}, inAppPrefix = ${inAppPrefix}, inCtxPrefix = ${inCtxPrefix}, inTyPrefix = ${inTyPrefix})", _ => s"~> ${t.expanded} (sym = ${t.resolvedSym}, typ = ${t.resolvedTyp})" ): // Resolve the sub-resolvable-terms of the term. val (defn, newICtx1) = t match + case _: Term.Resolved => lastWords(s"Term ${t} is already resolved.") + // Note: the arguments of the App are traversed later because the // definition is required. case Term.App(lhs: Resolvable, args) => val result = args match case t @ Term.CtxTup(_) => - resolve(lhs, prefer = prefer, inAppPrefix = true, inCtxPrefix = true, inTyPrefix = inTyPrefix) + resolve(lhs, prefer = Any, inAppPrefix = true, inCtxPrefix = true, inTyPrefix = inTyPrefix) case _ => - resolve(lhs, prefer = prefer, inAppPrefix = true, inCtxPrefix = inCtxPrefix, inTyPrefix = inTyPrefix) - resolveSymbol(t, prefer = prefer) + resolve(lhs, prefer = Any, inAppPrefix = true, inCtxPrefix = inCtxPrefix, inTyPrefix = inTyPrefix) + resolveSymbol(t, prefer = prefer, sign = false) resolveType(t, prefer = prefer) result case Term.App(lhs, _) => @@ -522,8 +541,8 @@ class Resolver(tl: TraceLogger) case Term.TyApp(lhs: Resolvable, targs) => resolve(lhs, prefer = prefer, inAppPrefix = inAppPrefix, inCtxPrefix = inCtxPrefix, inTyPrefix = true) - targs.foreach(traverse(_, expect = Any)) - resolveSymbol(t, prefer = prefer) + targs.foreach(traverseSign(_, expect = Any)) + resolveSymbol(t, prefer = prefer, sign = false) resolveType(t, prefer = prefer) (t.callableDefn, ictx) case Term.TyApp(lhs, targs) => @@ -531,26 +550,37 @@ class Resolver(tl: TraceLogger) targs.foreach(traverse(_, expect = Any)) (t.callableDefn, ictx) - case AnySel(pre: Resolvable, id) => - resolve(pre, prefer = prefer, inAppPrefix = false, inCtxPrefix = false, inTyPrefix = false) - resolveSymbol(t, prefer = prefer) + case AnySel(pre: Resolvable, id, cls) => + resolve(pre, prefer = Selectable(N), inAppPrefix = false, inCtxPrefix = false, inTyPrefix = false) + cls.foreach: + case cls: Resolvable => resolve(cls, prefer = Class(N), inAppPrefix = false, inCtxPrefix = false, inTyPrefix = false) + case cls => traverse(cls, expect = Class(N)) + resolveSymbol(t, prefer = prefer, sign = false) resolveType(t, prefer = prefer) (t.callableDefn, ictx) - case AnySel(pre, id) => - traverse(pre, expect = Any) + case AnySel(pre, id, cls) => + traverse(pre, expect = Selectable(N)) + cls.foreach(traverse(_, expect = Class(N))) + (t.callableDefn, ictx) + + case Term.New(cls, args, rft) => + // Term.New has only a type, but does not have a symbol. + traverse(cls, expect = Class(S("The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation."))) + args.foreach(traverse(_, expect = NonModule(N))) + resolveType(t, prefer = prefer) (t.callableDefn, ictx) case Term.Ref(_: BlockMemberSymbol) => - resolveSymbol(t, prefer = prefer) + resolveSymbol(t, prefer = prefer, sign = false) resolveType(t, prefer = prefer) (t.callableDefn, ictx) case Term.Ref(_) => - resolveSymbol(t, prefer = prefer) + resolveSymbol(t, prefer = prefer, sign = false) resolveType(t, prefer = prefer) (N, ictx) t.expandedResolvableIn: t => - log(s"Resolving resolvable term ${t} with sym = ${t.resolvedSym}, typ = ${t.resolvedTyp}: ${defn}") + log(s"Resolving resolvable term ${t} with sym = ${t.resolvedSym}, typ = ${t.resolvedTyp}") // Fill the context with possibly the type arguments information. val newICtx2 = newICtx1.givenIn: @@ -737,7 +767,7 @@ class Resolver(tl: TraceLogger) t.expand(S(expansion)) expansion match // * expansion may change the semantics, thus symbol is also changed case r: Resolvable => - resolveSymbol(r, prefer = prefer) + resolveSymbol(r, prefer = prefer, sign = false) resolveType(r, prefer = prefer) case _ => () @@ -749,6 +779,27 @@ class Resolver(tl: TraceLogger) t.dontResolve (N, ictx) + def disambSym(expect: Expect, sign: Bool)(bms: BlockMemberSymbol): Opt[DefinitionSymbol[?]] = + expect match + // If it is expecting a class or module specifically, cast the symbol. + case _: Module => bms.asMod + case _: Class => bms.asCls + case _: Selectable => bms.asModOrObj + // If it is expecting a generic symbol, use asPrinciple for the "default interpretation". + case _: (Any.type | NonModule) if sign => + bms.asTpe + case _: (Any.type | NonModule) => + bms.asPrincipal + case _: PatternConstructor => + bms.asCls orElse + bms.asObj orElse + bms.asAls orElse + bms.asPat orElse + bms.asMod orElse + bms.asTrm + + + /** * Resolve the symbol for a resolvable term, which was not resolved by * the elaborator due to unready definitions. After the symbol @@ -767,7 +818,7 @@ class Resolver(tl: TraceLogger) * This also expands the LHS `Foo` of a selection to `Foo.class` if * the selection is selecting a static member from a lifted module. */ - def resolveSymbol(t: Resolvable, prefer: Expect)(using ictx: ICtx): Unit = + def resolveSymbol(t: Resolvable, prefer: Expect, sign: Bool)(using ictx: ICtx): Unit = trace[Unit]( s"Resolving symbol for term: ${t} (prefer = ${prefer})", _ => s"-> (sym = ${t.resolvedSym}, typ = ${t.resolvedTyp})" @@ -789,25 +840,78 @@ class Resolver(tl: TraceLogger) // not try to resolve it again in the resolver. case _ if t.symbol.exists(_.isInstanceOf[ErrorSymbol]) => () - case t @ AnySel(lhs: Resolvable, id) => lhs.expandedResolvableIn: lhs => - log(s"Resolving symbol for ${t}, defn = ${lhs.defn}") - lhs.singletonDefn.foreach: mdef => - val fsym = mdef.body.members.get(id.name) + case t @ Term.Ref(bsym: BlockMemberSymbol) => + log(s"Resolving symbol for reference ${t} (bsym = ${bsym}, defn = ${bsym.defn})") + val sym = disambSym(prefer, sign = sign)(bsym) + sym.foreach: sym => + t.expand(S((t.duplicate.resolved(sym)))) + resolveType(t, prefer = prefer) + log(s"Resolved symbol for ${t}: ${sym}") + + case t @ AnySel(lhs: Resolvable, id, cls) => lhs.expandedResolvableIn: lhs => + log(s"Resolving symbol for selection ${t}, defn = ${lhs.defn}") + + val clsDefn = cls.flatMap: sym => + sym.resolvedSym.flatMap(_.asCls).map: clsSym => + clsSym.defn.getOrElse(die) + + // Singleton Definitions + lhs.singletonDefn.foreach: defn => + val fsym = defn.body.members.get(id.name) fsym match - case S(fldSym) => - val bsym = fldSym.asBlkMember.getOrElse: - lastWords(s"${mdef}: field symbol found ${fldSym} but no block member symbol") - log(s"Resolving symbol for ${t}, defn = ${lhs.defn}") - t.expand(S(t.withSym(bsym))) - expand2DotClass(lhs, expect = Expect.Module(N)) - log(s"Resolved symbol for ${t}: ${bsym}") - case N => - t.expand(S(t.withSym(ErrorSymbol(id.name, Tree.Dummy)))) - raise: - ErrorReport( - msg"${mdef.kind.desc.capitalize} '${mdef.sym.nme}' " + - msg"does not contain member '${id.name}'" -> t.toLoc :: Nil, - extraInfo = S(mdef)) + case S(bms: BlockMemberSymbol) => + log(s"Resolving symbol for ${t}, defn = ${lhs.defn}") + disambSym(prefer, sign)(bms) match + case S(ds) => + t.expand(S(t.withSym(bms).resolved(ds))) + case N => + log(s"Unable to disambiguate ${bms}") + t.expand(S(t.withSym(bms))) + log(s"Resolved symbol for ${t}: ${bms}") + case N => + t.expand(S(t.withSym(ErrorSymbol(id.name, Tree.Dummy)))) + raise: + ErrorReport( + msg"${defn.kind.desc.capitalize} '${defn.sym.nme}' " + + msg"does not contain member '${id.name}'" -> t.toLoc :: Nil, + extraInfo = S(defn)) + + // Class-Like Definitions + (clsDefn orElse lhs.typDefn).foreach: + case defn: ClassLikeDef => + // A reference to a member within the class is elaborated into a SynthSel, e.g., + // class C with + // fun f = 42 + // f + // The `f` in the body is elaborated into SynthSel(class:Foo, 'f'). + val fsym = defn.body.members.get(id.name) + fsym match + case S(bms: BlockMemberSymbol) => + log(s"Resolving symbol for ${t}, defn = ${lhs.defn}") + disambSym(prefer, sign)(bms) match + case S(ds) => + t.expand(S(t.withSym(bms).resolved(ds))) + case N => + log(s"Unable to disambiguate ${bms}") + t.expand(S(t.withSym(bms))) + log(s"Resolved symbol for ${t}: ${bms}") + case N => + // TODO @Harry: Appropriately resolve all selections on classes. + // - MLscript programs selecting JS members without properly defining them. + // - Inherited members. + case defn => + log(s"Unsupported selection from definition: ${defn}") + + case t @ Term.New(cls, _, N) => + // cls is already resolved, so the symbol should be present; + // otherwise, there is already an error raised. + cls.resolvedSym match + case S(clsSym: ClassSymbol) => + t.expand(S(t.duplicate.resolved(clsSym))) + case S(sym) => + lastWords(s"Expected a class symbol; found ${sym} for term ${t}.") + case N => + case _ => /** @@ -821,23 +925,23 @@ class Resolver(tl: TraceLogger) def resolveType(t: Resolvable, prefer: Expect)(using ictx: ICtx): Unit = t.expandedResolvableIn: t => trace[Unit]( s"Resolving the type for term: ${t} (prefer = ${prefer}, sym = ${t.resolvedSym})", - _ => s"-> (typ = ${t.resolvedTyp})" + _ => s"-> typ = ${t.resolvedTyp}" ): def disambSym(bms: BlockMemberSymbol): Opt[FieldSymbol] = prefer match case _: Module => bms.asMod case _: Class => bms.asCls - case _: NonModule => - val trmSym = bms.defn match - case S(defn: TermDefinition) => S(defn.tsym) - case _ => N - trmSym orElse bms.asPrincipal - case _: Any => bms.defn match - case S(defn: TermDefinition) => S(defn.tsym) - case S(defn: ClassDef) => S(defn.sym) - case S(defn: ModuleOrObjectDef) => S(defn.sym) - case _ => N + case _: Selectable => bms.asModOrObj + case _: (Any.type | NonModule) => bms.asPrincipal t match + case Term.New(cls, _, N) => cls.resolvedSym match + case S(clsSym: ClassSymbol) => + val ty = Type.Ref(clsSym, Nil) + t.expand(S(t.withTyp(ty))) + case _ => + // cls is already resolved, so the symbol should be present; + // otherwise, there is already an error raised. + () case t @ Apps(base: Resolvable, ass) => val decl = base.resolvedSym match case S(bms: BlockMemberSymbol) => @@ -845,7 +949,7 @@ class Resolver(tl: TraceLogger) log(s"Disambiguate ${bms} into ${disambBms} (defn = ${disambBms.map(_.defn)})") disambBms match case S(disambBms) => disambBms.defn - case N => bms.defn + case N => bms.asPrincipal.flatMap(_.defn) case S(bls: BlockLocalSymbol) => bls.decl case S(fs: FieldSymbol) => fs.defn case _ => N @@ -860,6 +964,11 @@ class Resolver(tl: TraceLogger) case S(defn: ModuleOrObjectDef) if ass.isEmpty => val ty = Type.Ref(defn.sym, Nil) t.expand(S(t.withTyp(ty))) + case S(defn: ClassDef) => base match + case Term.Ref(inner: InnerSymbol) => + val ty = Type.Ref(defn.sym, Nil) + t.expand(S(t.withTyp(ty))) + case _ => case _ => case _ => end resolveType @@ -928,8 +1037,8 @@ class Resolver(tl: TraceLogger) case Term.App(Term.Ref(_: BuiltinSymbol), Term.Tup(Fld(term = Term.Lit(_)) :: Nil)) => // Selection. The prefix should be a term, rather than a type, that - // can be selected from. - case AnySel(base, _) => + // can be selected from. This should not be a selection projection. + case AnySel(base, _, N) => base.subTerms.foreach(traverse(_, expect = Any)) // Type Application. Traverse the type constructor and arguments, @@ -948,14 +1057,18 @@ class Resolver(tl: TraceLogger) raise(ErrorReport(msg"Expected a type, got ${t.describe}" -> t.toLoc :: Nil)) return - val typ = resolveSign(t, expect = expect) + // * Resolve the symbol and type of the term. - t match + val typ = t match case t: Resolvable => - resolveSymbol(t, prefer = expect) + resolveSymbol(t, prefer = expect, sign = true) + val typ = resolveSign(t, expect = expect) t.expandedResolvableIn(_.withTyp(typ)) - case _ => () + typ + case _ => + val typ = resolveSign(t, expect = expect) + typ // * Check if the term satisfies the expectation. // * Check the arity of type params/args. @@ -980,7 +1093,7 @@ class Resolver(tl: TraceLogger) * Given a symbol-resolved term that represents a type, resolve the * type that it represents. */ - def resolveSign(t: Term, expect: Expect): Type = + def resolveSign(t: Term, expect: Expect): Type = def raiseError(sym: Opt[Symbol] = N) = val defnMsg = sym match case S(sym: FieldSymbol) => sym.defn match @@ -1049,9 +1162,10 @@ class Resolver(tl: TraceLogger) end Resolver object AnySel: - def unapply(t: (Term.Sel | Term.SynthSel)): S[(Term, Tree.Ident)] = t match - case Term.Sel(lhs, id) => S((lhs, id)) - case Term.SynthSel(lhs, id) => S((lhs, id)) + def unapply(t: (Term.Sel | Term.SynthSel | Term.SelProj)): S[(Term, Tree.Ident, Opt[Term])] = t match + case Term.Sel(lhs, id) => S((lhs, id, N)) + case Term.SynthSel(lhs, id) => S((lhs, id, N)) + case Term.SelProj(lhs, cls, proj) => S((lhs, proj, S(cls))) object ModuleChecker: diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Symbol.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Symbol.scala index 9290b61a16..05fd4b09c9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Symbol.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Symbol.scala @@ -53,7 +53,6 @@ abstract class Symbol(using State) extends Located: case _ => false - // * Not defining `asTrm` since `TermDef` curretly doesn't have a symbol def hasTrmDef: Bool = this match case trm: TermSymbol => true case mem: BlockMemberSymbol => mem.trmTree.nonEmpty @@ -70,12 +69,13 @@ abstract class Symbol(using State) extends Located: def asMod: Opt[ModuleOrObjectSymbol] = asModOrObj.filter(_.tree.k is Mod) def asObj: Opt[ModuleOrObjectSymbol] = asModOrObj.filter(_.tree.k is Obj) def asClsOrMod: Opt[ClassSymbol | ModuleOrObjectSymbol] = asCls orElse asModOrObj - /* + + // * This is a hack for that `TermDef` currently doesn't have a symbol. + // * So, the symbol is from the `TermDefinition`. def asTrm: Opt[TermSymbol] = this match case trm: TermSymbol => S(trm) - case mem: BlockMemberSymbol => mem.trmTree.flatMap(_.symbol.asTrm) + case mem: BlockMemberSymbol => mem.tsym case _ => N - */ def asPat: Opt[PatternSymbol] = this match case pat: PatternSymbol => S(pat) case mem: BlockMemberSymbol => mem.patTree.flatMap(_.symbol.asPat) @@ -88,8 +88,9 @@ abstract class Symbol(using State) extends Located: def asClsLike: Opt[ClassSymbol | ModuleOrObjectSymbol | PatternSymbol] = (asCls: Opt[ClassSymbol | ModuleOrObjectSymbol | PatternSymbol]) orElse asModOrObj orElse asPat def asTpe: Opt[TypeSymbol] = asCls - .orElse[TypeSymbol](asModOrObj) + .orElse[TypeSymbol](asObj) .orElse[TypeSymbol](asAls) + .orElse[TypeSymbol](asMod) def asNonModTpe: Opt[TypeSymbol] = asCls .orElse[TypeSymbol](asObj) .orElse[TypeSymbol](asAls) @@ -100,24 +101,27 @@ abstract class Symbol(using State) extends Located: case S(defn: TypeLikeDef) => S(defn.bsym) case S(defn: TermDefinition) => S(defn.sym) case N => N - + case _ => N + /** Get the symbol corresponding to the "representative" of a set of overloaded definitions, * or the sole definition, if it is not overloaded. * We should consider the ordering terms > classes/objects/types > modules, for this purpose. */ - def asPrincipal = + def asPrincipal: Opt[TermSymbol | ClassSymbol | ModuleOrObjectSymbol | TypeAliasSymbol | PatternSymbol] = + val asTrm: Opt[TermSymbol | ClassSymbol | ModuleOrObjectSymbol | TypeAliasSymbol | PatternSymbol] = this.asTrm + asTrm orElse asCls orElse asObj orElse asAls orElse asPat orElse asMod - + override def equals(x: Any): Bool = x match case that: Symbol => uid === that.uid case _ => false override def hashCode: Int = uid.hashCode - + def subst(using SymbolSubst): Symbol - + end Symbol @@ -197,6 +201,9 @@ class BuiltinSymbol class BlockMemberSymbol(val nme: Str, val trees: Ls[TypeOrTermDef], val nameIsMeaningful: Bool = true)(using State) extends MemberSymbol[Definition]: + // * This is a hack for that `TermDef` currently doesn't have a symbol. + var tsym: Opt[TermSymbol] = N + def toLoc: Option[Loc] = Loc(trees) def describe: Str = @@ -222,9 +229,6 @@ class BlockMemberSymbol(val nme: Str, val trees: Ls[TypeOrTermDef], val nameIsMe def isParameterizedMethod: Bool = trmTree.exists(_.isParameterizedMethod) - lazy val hasLiftedClass: Bool = - objTree.isDefined || trmTree.isDefined || clsTree.exists(_.paramLists.nonEmpty) - override def toString: Str = s"member:$nme${State.dbgUid(uid)}" @@ -240,11 +244,14 @@ sealed abstract class MemberSymbol[Defn <: Definition](using State) extends Symb class TermSymbol(val k: TermDefKind, val owner: Opt[InnerSymbol], val id: Tree.Ident)(using State) - extends MemberSymbol[Definition] with LocalSymbol with NamedSymbol: + extends MemberSymbol[TermDefinition] + with DefinitionSymbol[TermDefinition] + with LocalSymbol + with NamedSymbol: def nme: Str = id.name def name: Str = nme def toLoc: Option[Loc] = id.toLoc - override def toString: Str = s"${owner.getOrElse("")}.${id.name}" + override def toString: Str = s"term:${owner.map(o => s"${o}.").getOrElse("")}${id.name}${State.dbgUid(uid)}" def subst(using sub: SymbolSubst): TermSymbol = sub.mapTermSym(this) @@ -293,11 +300,33 @@ sealed trait ClassLikeSymbol extends IdentifiedSymbol: def subst(using sub: SymbolSubst): ClassLikeSymbol +/** + * A symbol for entities with a definition. + * + * This is different from `MemberSymbol` because `BlockMemberSymbol` extends `MemberSymbol`, and its + * definition is ambiguous in the sense that a `BlockMemberSymbol` corresponds to multiple + * overloaded definitions. In contrast, a `DefinitionSymbol` corresponds to only one specific + * definition. + */ +sealed trait DefinitionSymbol[Defn <: Definition] extends Symbol: + this: MemberSymbol[Defn] => + + def defn: Opt[Defn] + def subst(using sub: SymbolSubst): DefinitionSymbol[Defn] + + def asMemSym: MemberSymbol[Defn] = this + + /** This is the symbol associated to specific definitions. * One overloaded `BlockMemberSymbol` may correspond to multiple `InnerSymbol`s * A `Ref(_: InnerSymbol)` represents a `this`-like reference to the current object. */ // TODO prevent from appearing in Ref sealed trait InnerSymbol(using State) extends Symbol: + // Ideally, InnerSymbol should extend DefinitionSymbol, but that requires us to specify the type + // parameter to all occurrences of InnerSymbol. So, we use a self-type annotation instead to + // ensure that any implementation of InnerSymbol is also a DefinitionSymbol. + self: DefinitionSymbol[?] => + val privatesScope: Scope = Scope.empty // * Scope for private members of this symbol val thisProxy: TempSymbol = TempSymbol(N, s"this$$$nme") def subst(using SymbolSubst): InnerSymbol @@ -306,7 +335,12 @@ trait IdentifiedSymbol extends Symbol: val id: Tree.Ident class ClassSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using State) - extends MemberSymbol[ClassDef] with ClassLikeSymbol with CtorSymbol with InnerSymbol with NamedSymbol: + extends MemberSymbol[ClassDef] + with ClassLikeSymbol + with CtorSymbol + with DefinitionSymbol[ClassDef] + with InnerSymbol + with NamedSymbol: def name: Str = nme def nme = id.name def toLoc: Option[Loc] = id.toLoc // TODO track source tree of classe here @@ -317,7 +351,12 @@ class ClassSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using State) override def subst(using sub: SymbolSubst): ClassSymbol = sub.mapClsSym(this) class ModuleOrObjectSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using State) - extends MemberSymbol[ModuleOrObjectDef] with ClassLikeSymbol with CtorSymbol with InnerSymbol with NamedSymbol: + extends MemberSymbol[ModuleOrObjectDef] + with ClassLikeSymbol + with CtorSymbol + with DefinitionSymbol[ModuleOrObjectDef] + with InnerSymbol + with NamedSymbol: def name: Str = nme def nme = id.name def toLoc: Option[Loc] = id.toLoc // TODO track source tree of module here @@ -327,7 +366,9 @@ class ModuleOrObjectSymbol(val tree: Tree.TypeDef, val id: Tree.Ident)(using Sta override def subst(using sub: SymbolSubst): ModuleOrObjectSymbol = sub.mapModuleSym(this) -class TypeAliasSymbol(val id: Tree.Ident)(using State) extends MemberSymbol[TypeDef]: +class TypeAliasSymbol(val id: Tree.Ident)(using State) + extends MemberSymbol[TypeDef] + with DefinitionSymbol[TypeDef]: def nme = id.name def toLoc: Option[Loc] = id.toLoc // TODO track source tree of type alias here override def toString: Str = s"type:${id.name}${State.dbgUid(uid)}" @@ -335,7 +376,10 @@ class TypeAliasSymbol(val id: Tree.Ident)(using State) extends MemberSymbol[Type def subst(using sub: SymbolSubst): TypeAliasSymbol = sub.mapTypeAliasSym(this) class PatternSymbol(val id: Tree.Ident, val params: Opt[Tree.Tup], val body: Tree)(using State) - extends MemberSymbol[PatternDef] with CtorSymbol with InnerSymbol: + extends MemberSymbol[PatternDef] + with CtorSymbol + with DefinitionSymbol[PatternDef] + with InnerSymbol: def nme = id.name def toLoc: Option[Loc] = id.toLoc // TODO track source tree of pattern here override def toString: Str = s"pattern:${id.name}" @@ -343,7 +387,9 @@ class PatternSymbol(val id: Tree.Ident, val params: Opt[Tree.Tup], val body: Tre override def subst(using sub: SymbolSubst): PatternSymbol = sub.mapPatSym(this) class TopLevelSymbol(blockNme: Str)(using State) - extends MemberSymbol[ModuleOrObjectDef] with InnerSymbol: + extends MemberSymbol[ModuleOrObjectDef] + with DefinitionSymbol[ModuleOrObjectDef] + with InnerSymbol: def nme = blockNme def toLoc: Option[Loc] = N override def toString: Str = s"globalThis:$blockNme${State.dbgUid(uid)}" diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala index f39015fac8..961abca790 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala @@ -9,6 +9,7 @@ import syntax.* import Elaborator.State import hkmc2.typing.Type import hkmc2.semantics.Elaborator.{Ctx, ctx} +import hkmc2.Message.MessageContext final case class QuantVar(sym: VarSymbol, ub: Opt[Term], lb: Opt[Term]) @@ -54,11 +55,14 @@ sealed trait ResolvableImpl: def duplicate: this.type = this.match + case t: Term.Resolved => t.copy()(t.typ) case t: Term.Ref => t.copy()(t.tree, t.refNum, t.typ) case t: Term.App => t.copy()(t.tree, t.typ, t.resSym) case t: Term.TyApp => t.copy()(t.typ) case t: Term.Sel => t.copy()(t.sym, t.typ) case t: Term.SynthSel => t.copy()(t.sym, t.typ) + case t: Term.SelProj => t.copy()(t.sym, t.typ) + case t: Term.New => t.copy()(t.typ) .withLocOf(this) .asInstanceOf @@ -66,17 +70,21 @@ sealed trait ResolvableImpl: this.match case t: Term.Sel => t.copy()(S(sym), t.typ) case t: Term.SynthSel => t.copy()(S(sym), t.typ) + case t: Term.SelProj => t.copy()(S(sym), t.typ) case _ => lastWords(s"Cannot attach a symbol to a non-selection term: ${this.show}") .withLocOf(this) .asInstanceOf def withTyp(typ: Type): this.type = this.match + case t: Term.Resolved => t.copy()(S(typ)) case t: Term.Ref => t.copy()(t.tree, t.refNum, S(typ)) case t: Term.App => t.copy()(t.tree, S(typ), t.resSym) case t: Term.TyApp => t.copy()(S(typ)) case t: Term.Sel => t.copy()(t.sym, S(typ)) case t: Term.SynthSel => t.copy()(t.sym, S(typ)) + case t: Term.SelProj => t.copy()(t.sym, S(typ)) + case t: Term.New => t.copy()(S(typ)) .withLocOf(this) .asInstanceOf @@ -120,6 +128,12 @@ sealed trait ResolvableImpl: def resolve: this.type = expand(N) def dontResolve: this.type = this // TODO rm + /** + * A helper function to create a resolved term for this term. + */ + def resolved(sym: DefinitionSymbol[?]): Term.Resolved = + Term.Resolved(this, sym)(typ = resolvedTyp) + def hasExpansion = expansion.isDefined def defn: Opt[Definition] = resolvedSym match @@ -189,6 +203,10 @@ enum Term extends Statement: case UnitVal() case Missing // Placeholder terms that were not elaborated due to the "lightweight" elaboration mode `Mode.Light` case Lit(lit: Literal) + /** A term that wraps another term, indicating that the symbol of the inner term is resolved. + * This is mainly used to disambiguate overloaded definitions. */ + case Resolved(t: Term, sym: DefinitionSymbol[?]) + (val typ: Opt[Type]) extends Term, ResolvableImpl case Ref(sym: Symbol) (val tree: Tree.Ident, val refNum: Int, val typ: Opt[Type]) extends Term, ResolvableImpl case App(lhs: Term, rhs: Term) @@ -199,6 +217,8 @@ enum Term extends Statement: (val sym: Opt[FieldSymbol], val typ: Opt[Type]) extends Term, ResolvableImpl case SynthSel(prefix: Term, nme: Tree.Ident) (val sym: Opt[FieldSymbol], val typ: Opt[Type]) extends Term, ResolvableImpl + case SelProj(prefix: Term, cls: Term, proj: Tree.Ident) + (val sym: Opt[FieldSymbol], val typ: Opt[Type]) extends Term, ResolvableImpl case DynSel(prefix: Term, fld: Term, arrayIdx: Bool) case Tup(fields: Ls[Elem])(val tree: Tree.Tup) case Mut(underlying: Tup | Rcd | New | DynNew) @@ -213,8 +233,8 @@ enum Term extends Statement: case Quoted(body: Term) case Unquoted(body: Term) case New(cls: Term, args: Ls[Term], rft: Opt[ClassSymbol -> ObjBody]) + (val typ: Opt[Type]) extends Term, ResolvableImpl case DynNew(cls: Term, args: Ls[Term]) - case SelProj(prefix: Term, cls: Term, proj: Tree.Ident)(val sym: Opt[FieldSymbol]) case Asc(term: Term, ty: Term) case CompType(lhs: Term, rhs: Term, pol: Bool) case Neg(rhs: Term) @@ -243,6 +263,7 @@ enum Term extends Statement: * elaboration. */ lazy val symbol: Opt[Symbol] = this match + case res: Resolved => S(res.sym) case Ref(sym) => S(sym) case sel: Sel => sel.sym case sel: SynthSel => sel.sym @@ -255,6 +276,7 @@ enum Term extends Statement: * symbol is resolved during the resolution stage. */ def resolvedSym: Opt[Symbol] = expanded match + case res: Resolved => S(res.sym) case ref: Ref => ref.symbol case sel: Sel => sel.sym case sel: SynthSel => sel.sym @@ -263,11 +285,13 @@ enum Term extends Statement: case _ => N def resolvedTyp: Opt[Type] = expanded match + case res: Resolved => res.typ case ref: Ref => ref.typ case app: App => app.typ case app: TyApp => app.typ case sel: Sel => sel.typ case sel: SynthSel => sel.typ + case nu: New => nu.typ case _ => N def sel(id: Tree.Ident, sym: Opt[FieldSymbol]): Sel = @@ -291,6 +315,7 @@ enum Term extends Statement: case Lit(Tree.DecLit(value)) => Lit(Tree.DecLit(value)) case Lit(Tree.BoolLit(value)) => Lit(Tree.BoolLit(value)) case Lit(Tree.UnitLit(value)) => Lit(Tree.UnitLit(value)) + case term @ Resolved(t, sym) => Resolved(t.mkClone, sym)(term.typ) case term @ Ref(sym) => Ref(sym)(Tree.Ident(term.tree.name), term.refNum, term.typ) case term @ Sel(prefix, nme) => Sel(prefix.mkClone, Tree.Ident(nme.name))(term.sym, term.typ) case term @ App(lhs, rhs) => App(lhs.mkClone, rhs.mkClone)(term.tree, term.typ, term.resSym) @@ -315,11 +340,11 @@ enum Term extends Statement: case Rcd(mut, stats) => Rcd(mut, stats.map(_.mkClone)) case Quoted(body) => Quoted(body.mkClone) case Unquoted(body) => Unquoted(body.mkClone) - case New(cls, args, rft) => - New(cls.mkClone, args.map(_.mkClone), rft.map { case (cs, ob) => cs -> ObjBody(ob.blk.mkBlkClone) }) + case term @ New(cls, args, rft) => + New(cls.mkClone, args.map(_.mkClone), rft.map { case (cs, ob) => cs -> ObjBody(ob.blk.mkBlkClone) })(term.typ) case DynNew(cls, args) => DynNew(cls.mkClone, args.map(_.mkClone)) case term @ SelProj(prefix, cls, proj) => - SelProj(prefix.mkClone, cls.mkClone, Tree.Ident(proj.name))(term.sym) + SelProj(prefix.mkClone, cls.mkClone, Tree.Ident(proj.name))(term.sym, term.typ) case Asc(term, ty) => Asc(term.mkClone, ty.mkClone) case CompType(lhs, rhs, pol) => CompType(lhs.mkClone, rhs.mkClone, pol) case Neg(rhs) => Neg(rhs.mkClone) @@ -395,6 +420,7 @@ sealed trait Statement extends AutoLocated, ProductWithExtraInfo: case Annotated(annotation, target) => "annotation" case Ret(res) => "return" case Try(body, finallyDo) => "try expression" + case Resolved(t, sym) => t.describe case s => TODO(s) this match case self: Resolvable => self.resolvedTyp match @@ -415,6 +441,7 @@ sealed trait Statement extends AutoLocated, ProductWithExtraInfo: case _ => subTerms def subTerms: Ls[Term] = this match case Error | Missing | _: Lit | _: Ref | _: UnitVal => Nil + case Resolved(t, sym) => t :: Nil case App(lhs, rhs) => lhs :: rhs :: Nil case RcdField(lhs, rhs) => lhs :: rhs :: Nil case RcdSpread(bod) => bod :: Nil @@ -488,6 +515,8 @@ sealed trait Statement extends AutoLocated, ProductWithExtraInfo: def showDbg: Str = this match case r: Ref => showPlain + case r: Resolved => + s"${r.showPlain}‹${r.sym}›" case trm: Term => // s"$showPlain‹${trm.symbol.getOrElse("")}›" s"$showPlain${trm.symbol.fold("")("‹"+_+"›")}" @@ -501,6 +530,7 @@ sealed trait Statement extends AutoLocated, ProductWithExtraInfo: def showPlain: Str = this match case Term.UnitVal() => "()" case Lit(lit) => lit.idStr + case Resolved(t, sym) => t.showPlain case r @ Ref(symbol) => symbol.toString + symbol.getState.dbgRefNum(r.refNum) case App(lhs, rhs) => s"${lhs.showDbg}${rhs.showAsParams}" case RcdField(lhs, rhs) => s"${lhs.showDbg}: ${rhs.showDbg}" @@ -649,13 +679,34 @@ final case class HandlerTermDefinition( td: TermDefinition ) +object ObjBody: + + def extractMembers(blk: Term.Blk): Ls[ErrorReport] \/ Map[Str, BlockMemberSymbol] = + val (errs, mems) = blk.stats.collect: + case td: TermDefinition => td.sym -> td + case td: ClassLikeDef => td.bsym -> td + case td: TypeDef => td.bsym -> td + .groupBy(_._1.nme) + .partitionMap: (nme, syms) => + if syms.map(_._1).distinct.tail.nonEmpty then L: + (msg"Duplicate definition of member named '${nme}'." -> N) :: + syms.map(_._2).map(msg"Defined at: " -> _.toLoc) + else R: + nme -> syms.head._1 + + if errs.nonEmpty then + L(errs.map(ErrorReport(_)).toList) + else + R(mems.toMap) + case class ObjBody(blk: Term.Blk): - lazy val members: Map[Str, FieldSymbol] = blk.stats.collect: - case td: TermDefinition => td.sym.nme -> td.sym - case td: ClassLikeDef => td.sym.nme -> td.sym - case td: TypeDef => td.sym.nme -> td.sym - .toMap + lazy val members: Map[Str, BlockMemberSymbol] = + ObjBody.extractMembers(blk) match + case L(errs) => lastWords: + errs.map(_.mainMsg).mkString("\n") + case R(mems) => + mems lazy val (methods, nonMethods) = blk.stats.partitionMap: case td: TermDefinition if td.k is syntax.Fun => L(td) @@ -694,7 +745,7 @@ sealed abstract class TypeLikeDef extends Definition: sealed abstract class ClassLikeDef extends TypeLikeDef: val owner: Opt[InnerSymbol] val kind: ClsLikeKind - val sym: MemberSymbol[? <: ClassLikeDef] & InnerSymbol + val sym: DefinitionSymbol[? <: ClassLikeDef] & InnerSymbol val bsym: BlockMemberSymbol val tparams: Ls[TyParam] val paramsOpt: Opt[ParamList] diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala index 3547b3fc7b..cacbf97d96 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/Normalization.scala @@ -38,21 +38,6 @@ class Normalization(using tl: TL)(using Raise, Ctx, State) extends TermSynthesiz case Split.Cons(head, tail) => Split.Cons(head, tail ++ those) case Split.Let(name, term, tail) => Split.Let(name, term, tail ++ those) case Split.Else(_) /* impossible */ | Split.End => those) - - extension (lhs: FlatPattern.ClassLike) - /** Generate a term that really resolves to the class at runtime. */ - def selectClass: FlatPattern.ClassLike = - val constructor = lhs.constructor.symbol match - case S(cls: ClassSymbol) => lhs.constructor - case S(mem: BlockMemberSymbol) => - // If the class is declaration-only, we do not need to select the - // class. - if !mem.hasLiftedClass || mem.defn.exists(_.hasDeclareModifier.isDefined) then - lhs.constructor - else - Term.SynthSel(lhs.constructor, Tree.Ident("class"))(mem.clsTree.orElse(mem.modOrObjTree).map(_.symbol), N).resolve - case _ => lhs.constructor - lhs.copy(constructor)(lhs.tree, lhs.output) extension (lhs: FlatPattern) /** Checks if two patterns are the same. */ @@ -173,7 +158,7 @@ class Normalization(using tl: TL)(using Raise, Ctx, State) extends TermSynthesiz val whenTrue = aliasOutputSymbols(scrutinee, pattern.output, normalize(specialize(consequent ++ alternative, +, scrutinee, pattern))) val whenFalse = normalizeImpl(specialize(alternative, -, scrutinee, pattern).clearFallback) - Branch(scrutinee, pattern.selectClass, whenTrue) ~: whenFalse + Branch(scrutinee, pattern, whenTrue) ~: whenFalse else // If any errors were raised, we skip the branch. log("BROKEN"); normalizeImpl(alternative) case S(S(mod: ModuleOrObjectSymbol)) => @@ -182,7 +167,7 @@ class Normalization(using tl: TL)(using Raise, Ctx, State) extends TermSynthesiz val whenTrue = aliasOutputSymbols(scrutinee, pattern.output, normalize(specialize(consequent ++ alternative, +, scrutinee, pattern))) val whenFalse = normalizeImpl(specialize(alternative, -, scrutinee, pattern).clearFallback) - Branch(scrutinee, pattern.selectClass, whenTrue) ~: whenFalse + Branch(scrutinee, pattern, whenTrue) ~: whenFalse else // If any errors were raised, we skip the branch. log("BROKEN"); normalizeImpl(alternative) case S(S(pat: PatternSymbol)) => mode match diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/TermSynthesizer.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/TermSynthesizer.scala index c2d013cda5..581ce1f810 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/TermSynthesizer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/ucs/TermSynthesizer.scala @@ -26,6 +26,8 @@ trait TermSynthesizer(using Ctx, State): protected final def app(l: Term, r: Term, label: Str): Term.App = app(l, r, FlowSymbol(label)) protected final def app(l: Term, r: Term, s: FlowSymbol): Term.App = (Term.App(l, r)(App(Dummy, Dummy), N, s): Term.App).resolve + protected final def `new`(cls: Term, args: Ls[Term], label: Str): Term.New = + Term.New(cls, args, N)(N) protected final def rcd(fields: RcdField*): Term.Rcd = Term.Rcd(false, fields.toList) protected final def splitLet(sym: BlockLocalSymbol, term: Term)(inner: Split): Split = @@ -38,19 +40,19 @@ trait TermSynthesizer(using Ctx, State): /** Make a term that looks like `runtime.MatchResult` with its symbol. */ protected lazy val matchResultClass = - sel(runtimeRef, "MatchResult", State.matchResultClsSymbol) + sel(runtimeRef, "MatchResult", State.matchResultClsSymbol).resolved(State.matchResultClsSymbol) /** Make a pattern that looks like `runtime.MatchResult.class`. */ protected def matchResultPattern(parameters: Opt[Ls[BlockLocalSymbol]]): FlatPattern.ClassLike = - FlatPattern.ClassLike(sel(matchResultClass, "class", State.matchResultClsSymbol), parameters) + FlatPattern.ClassLike(matchResultClass, parameters) /** Make a term that looks like `runtime.MatchFailure` with its symbol. */ protected lazy val matchFailureClass = - sel(runtimeRef, "MatchFailure", State.matchFailureClsSymbol) + sel(runtimeRef, "MatchFailure", State.matchFailureClsSymbol).resolved(State.matchFailureClsSymbol) /** Make a pattern that looks like `runtime.MatchFailure.class`. */ protected def matchFailurePattern(parameters: Opt[Ls[BlockLocalSymbol]]): FlatPattern.ClassLike = - FlatPattern.ClassLike(sel(matchFailureClass, "class", State.matchFailureClsSymbol), parameters) + FlatPattern.ClassLike(matchFailureClass, parameters) protected lazy val tupleSlice = sel(sel(runtimeRef, "Tuple"), "slice") protected lazy val tupleLazySlice = sel(sel(runtimeRef, "Tuple"), "lazySlice") @@ -97,16 +99,16 @@ trait TermSynthesizer(using Ctx, State): Split.Let(s, cond, Branch(s.safeRef, inner) ~: Split.End) protected final def makeMatchResult(output: Term) = - app(matchResultClass, tup(fld(output), fld(rcd())), "result of `MatchResult`") + `new`(matchResultClass, tup(fld(output), fld(rcd())) :: Nil, "result of `MatchResult`") protected final def makeMatchResult(output: Term, bindings: Term) = - app(matchResultClass, tup(fld(output), fld(bindings)), "result of `MatchResult`") + `new`(matchResultClass, tup(fld(output), fld(bindings)) :: Nil, "result of `MatchResult`") protected final def makeMatchResult(output: Term, fields: Ls[RcdField | RcdSpread]) = - app(matchResultClass, tup(fld(output), fld(Term.Rcd(false, fields))), "result of `MatchResult`") + `new`(matchResultClass, tup(fld(output), fld(Term.Rcd(false, fields))) :: Nil, "result of `MatchResult`") protected final def makeMatchFailure(errors: Term = Term.Lit(UnitLit(true))) = - app(matchFailureClass, tup(fld(errors)), "result of `MatchFailure`") + `new`(matchFailureClass, tup(fld(errors)) :: Nil, "result of `MatchFailure`") /** Make a `Branch` that calls `Pattern` symbols' `unapply` functions. */ def makeLocalPatternBranch( diff --git a/hkmc2/shared/src/main/scala/hkmc2/semantics/ups/Compiler.scala b/hkmc2/shared/src/main/scala/hkmc2/semantics/ups/Compiler.scala index 8e6eb3c525..9cd2ec6cc7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/semantics/ups/Compiler.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/semantics/ups/Compiler.scala @@ -408,14 +408,14 @@ object Compiler: def findSymbol(elem: Ctx.Elem): Opt[Term] = elem.symbol.flatMap(_.asClsLike).collectFirst: // Check the element's symbol. - case `symbol` => S(elem.ref(new Ident(symbol.nme)).withLoc(loc)) + case `symbol` => S(elem.ref(new Ident(symbol.nme)).withLoc(loc).resolved(symbol)) // Look up the symbol in module members. case module: ModuleOrObjectSymbol => val moduleRef = module.defn.get.bsym.ref() module.tree.definedSymbols.iterator.map(_.mapSecond(_.asClsLike)).collectFirst: case (key, S(`symbol`)) => val memberSymbol = symbol.defn.get.bsym - SynthSel(moduleRef, Ident(key))(S(memberSymbol), N) + SynthSel(moduleRef, Ident(key))(S(memberSymbol), N).resolved(symbol) .flatten @tailrec def go(ctx: Ctx): Opt[Term] = ctx.env.values.iterator.map(findSymbol).firstSome match @@ -423,12 +423,7 @@ object Compiler: case N => ctx.parent match case N => N case S(parent) => go(parent) - go(ctx).map: term => - // If the `symbol` is a virtual class, then do not select `class`. - symbol match - case s: ClassSymbol if !(ctx.builtins.virtualClasses contains s) => - SynthSel(term, Ident("class"))(S(s), N).resolve - case _: (ClassSymbol | ModuleOrObjectSymbol | PatternSymbol) => term + go(ctx) import Pattern.* diff --git a/hkmc2/shared/src/test/mlscript/OverloadedModulesInSignatures.mls b/hkmc2/shared/src/test/mlscript/OverloadedModulesInSignatures.mls index 065d7fa522..69abb2d790 100644 --- a/hkmc2/shared/src/test/mlscript/OverloadedModulesInSignatures.mls +++ b/hkmc2/shared/src/test/mlscript/OverloadedModulesInSignatures.mls @@ -30,7 +30,9 @@ f //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:f,typ=class:ClsMod} of member:f +//│ res = Resolved{sym=term:f,typ=class:ClsMod}: +//│ t = Ref{sym=member:f} of member:f +//│ sym = term:f //│ = 42 fun f: module ClsMod = ClsMod @@ -40,7 +42,9 @@ f //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:f,typ=module:ClsMod} of member:f +//│ res = Resolved{sym=term:f,typ=module:ClsMod}: +//│ t = Ref{sym=member:f} of member:f +//│ sym = term:f //│ = class ClsMod { whoami: "module" } fun f: TypMod = 42 @@ -50,7 +54,9 @@ f //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:f,typ=type:TypMod} of member:f +//│ res = Resolved{sym=term:f,typ=type:TypMod}: +//│ t = Ref{sym=member:f} of member:f +//│ sym = term:f //│ = 42 fun f: module TypMod = TypMod @@ -60,38 +66,33 @@ f //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:f,typ=module:TypMod} of member:f +//│ res = Resolved{sym=term:f,typ=module:TypMod}: +//│ t = Ref{sym=member:f} of member:f +//│ sym = term:f //│ = class TypMod { whoami: "module" } :e fun f: TrmMod = 42 -//│ ╔══[ERROR] Expected a non-module type; found reference denoting module 'TrmMod'. -//│ ║ l.67: fun f: TrmMod = 42 +//│ ╔══[ERROR] Expected a non-module type; found reference of type TrmMod denoting module 'TrmMod'. +//│ ║ l.75: fun f: TrmMod = 42 //│ ║ ^^^^^^ //│ ╙── Function must be marked as returning a 'module' in order to have a module return type. -// * FIXME: Should compile to term (function) `TrmMod` rather than module `TrmMod` -// * FIXME: Should module-check as the term module (or probably we will remove module-checks before that) :sjs -:fixme fun f = TrmMod -//│ ╔══[ERROR] Unexpected moduleful reference of type TrmMod. -//│ ║ l.77: fun f = TrmMod -//│ ║ ^^^^^^ -//│ ╙── Function must be marked as returning a 'module' in order to return a module. //│ JS (unsanitized): -//│ let f5; f5 = function f() { return TrmMod1 }; +//│ let f5; f5 = function f() { let tmp4; tmp4 = TrmMod1(); return tmp4 }; :fixme :expect 42 f -//│ ═══[RUNTIME ERROR] Expected: '42', got: 'class TrmMod { whoami: "module" }' -//│ = class TrmMod { whoami: "module" } +//│ ═══[RUNTIME ERROR] TypeError: Class constructor TrmMod cannot be invoked without 'new' +//│ ═══[RUNTIME ERROR] Expected: '42', got: 'undefined' :sjs fun f: module TrmMod = TrmMod //│ JS (unsanitized): -//│ let f6; f6 = function f() { return TrmMod1 }; +//│ let f6; f6 = function f() { return TrmMod1.class }; fun assertModule(module m: ClsMod): module ClsMod = m @@ -101,8 +102,9 @@ assertModule(ClsMod).whoami assertModule(TypMod).whoami //│ = "module" +:fixme assertModule(TrmMod).whoami -//│ = "module" +//│ ═══[RUNTIME ERROR] TypeError: Class constructor TrmMod cannot be invoked without 'new' fun assertNonModule(m) = m @@ -122,11 +124,7 @@ assertNonModule(TypMod).whoami :breakme :fixme assertNonModule(TrmMod).whoami -//│ ╔══[ERROR] Unexpected moduleful reference of type TrmMod. -//│ ║ l.124: assertNonModule(TrmMod).whoami -//│ ║ ^^^^^^ -//│ ╙── Module argument passed to a non-module parameter. -//│ = "module" +//│ ═══[RUNTIME ERROR] TypeError: Class constructor TrmMod cannot be invoked without 'new' type Foo[A] = Int @@ -135,10 +133,10 @@ module Foo :e fun f(x: Foo): Foo = x //│ ╔══[ERROR] Expected 1 type arguments, got none -//│ ║ l.136: fun f(x: Foo): Foo = x +//│ ║ l.134: fun f(x: Foo): Foo = x //│ ╙── ^^^ //│ ╔══[ERROR] Expected 1 type arguments, got none -//│ ║ l.136: fun f(x: Foo): Foo = x +//│ ║ l.134: fun f(x: Foo): Foo = x //│ ╙── ^^^ fun f(x: Foo[Int]): Foo[Int] = x @@ -148,10 +146,10 @@ fun f(module x: Foo): module Foo = x :e fun f(module x: Foo[Int]): module Foo[Int] = x //│ ╔══[ERROR] Expected no type arguments, got 1 -//│ ║ l.149: fun f(module x: Foo[Int]): module Foo[Int] = x +//│ ║ l.147: fun f(module x: Foo[Int]): module Foo[Int] = x //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Expected no type arguments, got 1 -//│ ║ l.149: fun f(module x: Foo[Int]): module Foo[Int] = x +//│ ║ l.147: fun f(module x: Foo[Int]): module Foo[Int] = x //│ ╙── ^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls b/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls index d3afd69e69..495a749c0e 100644 --- a/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls +++ b/hkmc2/shared/src/test/mlscript/backlog/Lifter.mls @@ -40,9 +40,13 @@ f(2) data class A(x) with data class B(y) with fun getB() = x + y - fun getA() = this.B(2).getB() + fun getA() = + // NOTE: The Term.Resolved PR made it so `this.B` gets resolved correctly. + // Explicitly binding `t = this` reproduces the previous error + let t = this + t.B(2).getB() A(1).getA() -//│ ═══[RUNTIME ERROR] TypeError: this.B is not a function +//│ ═══[RUNTIME ERROR] TypeError: t.B is not a function //│ ═══[RUNTIME ERROR] Expected: '3', got: 'undefined' // This is due to the order of classes after lifting @@ -195,7 +199,7 @@ fun foo(x) = (new Bar).self2 foo(2) //│ ╔══[ERROR] Expected a statically known class; found reference of type Foo. -//│ ║ l.194: class Bar extends Foo +//│ ║ l.198: class Bar extends Foo //│ ║ ^^^ //│ ╙── The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation. //│ ═══[COMPILATION ERROR] No definition found in scope for member 'Foo$' diff --git a/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls b/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls index 27b024ac01..963dbf98f9 100644 --- a/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls +++ b/hkmc2/shared/src/test/mlscript/backlog/NewWith.mls @@ -77,7 +77,7 @@ new Foo(123) with { fun foo = 27 } :e :re new (Foo(123)) with { fun foo = 27 } -//│ ╔══[ERROR] Expected a statically known class; found application. +//│ ╔══[ERROR] Expected a statically known class; found application of type Foo. //│ ║ l.79: new (Foo(123)) with { fun foo = 27 } //│ ║ ^^^^^^^^ //│ ╙── The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation. @@ -93,7 +93,7 @@ new! (Foo(123)) with { fun foo = 27 } :e :re new {Foo(123)} with { fun foo = 27 } -//│ ╔══[ERROR] Expected a statically known class; found application. +//│ ╔══[ERROR] Expected a statically known class; found application of type Foo. //│ ║ l.95: new {Foo(123)} with { fun foo = 27 } //│ ║ ^^^^^^^^ //│ ╙── The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation. diff --git a/hkmc2/shared/src/test/mlscript/basics/BadMemberProjections.mls b/hkmc2/shared/src/test/mlscript/basics/BadMemberProjections.mls index 917d9f6a02..3873c91b9a 100644 --- a/hkmc2/shared/src/test/mlscript/basics/BadMemberProjections.mls +++ b/hkmc2/shared/src/test/mlscript/basics/BadMemberProjections.mls @@ -9,6 +9,9 @@ //│ ║ ^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ╔══[ERROR] Expected a statically known class; found integer literal. +//│ ║ l.6: 1::x +//│ ╙── ^ //│ JS (unsanitized): //│ let lambda; //│ lambda = (undefined, function (self, ...args) { return runtime.safeCall(self.x(...args)) }); @@ -20,10 +23,13 @@ :re 1::x() //│ ╔══[ERROR] Integer literal is not a known class. -//│ ║ l.21: 1::x() +//│ ║ l.24: 1::x() //│ ║ ^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ╔══[ERROR] Expected a statically known class; found integer literal. +//│ ║ l.24: 1::x() +//│ ╙── ^ //│ JS: //│ lambda1 = (undefined, function (...args1) { //│ runtime.checkArgs("", 1, false, args1.length); @@ -50,19 +56,25 @@ let x = 1 :e "A"::x //│ ╔══[ERROR] String literal is not a known class. -//│ ║ l.51: "A"::x +//│ ║ l.57: "A"::x //│ ║ ^^^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ╔══[ERROR] Expected a statically known class; found string literal. +//│ ║ l.57: "A"::x +//│ ╙── ^^^ //│ = fun :e "A" ::x //│ ╔══[ERROR] String literal is not a known class. -//│ ║ l.60: "A" ::x +//│ ║ l.69: "A" ::x //│ ║ ^^^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ╔══[ERROR] Expected a statically known class; found string literal. +//│ ║ l.69: "A" ::x +//│ ╙── ^^^ //│ = fun diff --git a/hkmc2/shared/src/test/mlscript/basics/CompanionModules_Classes.mls b/hkmc2/shared/src/test/mlscript/basics/CompanionModules_Classes.mls index 6cef84654f..ced354b8b2 100644 --- a/hkmc2/shared/src/test/mlscript/basics/CompanionModules_Classes.mls +++ b/hkmc2/shared/src/test/mlscript/basics/CompanionModules_Classes.mls @@ -10,8 +10,10 @@ C() //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = App: -//│ lhs = Ref{sym=member:C,typ=module:C} of member:C +//│ res = App{typ=class:C}: +//│ lhs = Resolved{sym=term:class:C.C}: +//│ t = Ref{sym=member:C} of member:C +//│ sym = term:class:C.C //│ rhs = Tup of Nil //│ = C() @@ -20,10 +22,10 @@ new C //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = New: -//│ cls = SynthSel{sym=class:C,typ=class:C}: -//│ prefix = Ref{sym=member:C} of member:C -//│ nme = Ident of "class" +//│ res = New{typ=class:C}: +//│ cls = Resolved{sym=class:C}: +//│ t = Ref{sym=member:C} of member:C +//│ sym = class:C //│ args = Nil //│ rft = N //│ = C() @@ -36,11 +38,13 @@ C.empty //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:empty}: -//│ prefix = SynthSel{sym=module:C,typ=module:C}: -//│ prefix = Ref{sym=member:C,typ=module:C} of member:C -//│ nme = Ident of "class" -//│ nme = Ident of "empty" +//│ res = Resolved{sym=term:module:C.empty}: +//│ t = Sel{sym=member:empty}: +//│ prefix = Resolved{sym=module:C,typ=module:C}: +//│ t = Ref{sym=member:C} of member:C +//│ sym = module:C +//│ nme = Ident of "empty" +//│ sym = term:module:C.empty //│ = 1 :breakme // TODO: should be an error, down the line, when we resolve all selections statically @@ -59,9 +63,13 @@ C.empty //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:empty}: -//│ prefix = Ref{sym=member:C,typ=module:C} of member:C -//│ nme = Ident of "empty" +//│ res = Resolved{sym=term:module:C.empty}: +//│ t = Sel{sym=member:empty}: +//│ prefix = Resolved{sym=module:C,typ=module:C}: +//│ t = Ref{sym=member:C} of member:C +//│ sym = module:C +//│ nme = Ident of "empty" +//│ sym = term:module:C.empty //│ = 1 diff --git a/hkmc2/shared/src/test/mlscript/basics/DataClass.mls b/hkmc2/shared/src/test/mlscript/basics/DataClass.mls index ac2c22fc22..f442475c8c 100644 --- a/hkmc2/shared/src/test/mlscript/basics/DataClass.mls +++ b/hkmc2/shared/src/test/mlscript/basics/DataClass.mls @@ -11,7 +11,7 @@ Foo(1).x :todo data Foo(x: Int) //│ ╔══[WARNING] This annotation has no effect. -//│ ╟── Such annotations are not supported on application terms. +//│ ╟── Such annotations are not supported on application of type Foo terms. //│ ║ l.12: data Foo(x: Int) //│ ╙── ^^^^^^^^^^^ //│ ╔══[COMPILATION ERROR] Symbol 'Int' is virtual (i.e., "compiler fiction"); cannot be used as a term diff --git a/hkmc2/shared/src/test/mlscript/basics/MemberProjections.mls b/hkmc2/shared/src/test/mlscript/basics/MemberProjections.mls index 8a945a7d69..c22fcf695c 100644 --- a/hkmc2/shared/src/test/mlscript/basics/MemberProjections.mls +++ b/hkmc2/shared/src/test/mlscript/basics/MemberProjections.mls @@ -81,13 +81,14 @@ foo.Foo#m() //│ ╔══[ERROR] Identifier `Foo` does not name a known class symbol. //│ ║ l.77: foo.Foo#m() //│ ╙── ^^^^ +//│ ═══[ERROR] Expected a statically known class; found ‹error›. //│ = 124 :e :re foo.M.Foo::m() //│ ╔══[ERROR] Selection is not a known class. -//│ ║ l.88: foo.M.Foo::m() +//│ ║ l.89: foo.M.Foo::m() //│ ║ ^^^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. @@ -97,36 +98,39 @@ foo.M.Foo::m() :re foo.M.Foo#m() //│ ╔══[ERROR] Name not found: Foo -//│ ║ l.98: foo.M.Foo#m() +//│ ║ l.99: foo.M.Foo#m() //│ ╙── ^^^^ //│ ╔══[ERROR] Identifier `Foo` does not name a known class symbol. -//│ ║ l.98: foo.M.Foo#m() +//│ ║ l.99: foo.M.Foo#m() //│ ╙── ^^^^ +//│ ═══[ERROR] Expected a statically known class; found ‹error›. //│ ═══[RUNTIME ERROR] Error: Access to required field 'M' yielded 'undefined' :e Foo::m //│ ╔══[ERROR] Name not found: Foo -//│ ║ l.108: Foo::m +//│ ║ l.110: Foo::m //│ ╙── ^^^ //│ ╔══[ERROR] Identifier is not a known class. -//│ ║ l.108: Foo::m +//│ ║ l.110: Foo::m //│ ║ ^^^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ═══[ERROR] Expected a statically known class; found ‹error›. //│ = fun :e :sjs Foo::n(foo, 2) //│ ╔══[ERROR] Name not found: Foo -//│ ║ l.121: Foo::n(foo, 2) +//│ ║ l.124: Foo::n(foo, 2) //│ ╙── ^^^ //│ ╔══[ERROR] Identifier is not a known class. -//│ ║ l.121: Foo::n(foo, 2) +//│ ║ l.124: Foo::n(foo, 2) //│ ║ ^^^ //│ ╟── Note: any expression of the form `‹expression›::‹identifier›` is a member projection; //│ ╙── add a space before ‹identifier› to make it an operator application. +//│ ═══[ERROR] Expected a statically known class; found ‹error›. //│ JS (unsanitized): //│ let lambda9; //│ lambda9 = (undefined, function (self, ...args) { diff --git a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls index b259aa3ad8..9df8d9038b 100644 --- a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls +++ b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls @@ -7,7 +7,7 @@ module MM[T] :e fun f(m: M) -//│ ╔══[ERROR] Expected a non-module type; found reference denoting module 'M'. +//│ ╔══[ERROR] Expected a non-module type; found reference of type M denoting module 'M'. //│ ║ l.9: fun f(m: M) //│ ║ ^ //│ ╙── Non-module parameter must have a non-module type. @@ -67,7 +67,7 @@ fun f() = M :e fun f(): M = M -//│ ╔══[ERROR] Expected a non-module type; found reference denoting module 'M'. +//│ ╔══[ERROR] Expected a non-module type; found reference of type M denoting module 'M'. //│ ║ l.69: fun f(): M = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to have a module return type. @@ -173,7 +173,7 @@ class C with val bar: module M = M //│ ╔══[ERROR] Function returning modules should not be a class member. //│ ║ l.172: fun foo: module M = M -//│ ╙── ^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Value returning modules should not be a class member. //│ ║ l.173: val bar: module M = M -//│ ╙── ^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbErrors.mls b/hkmc2/shared/src/test/mlscript/bbml/bbErrors.mls index 1721148967..1988eb6c99 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbErrors.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbErrors.mls @@ -27,6 +27,7 @@ //│ ╔══[ERROR] Identifier `Foo` does not name a known class symbol. //│ ║ l.23: (1).Foo#a() //│ ╙── ^^^^ +//│ ═══[ERROR] Expected a statically known class; found ‹error›. //│ ═══[ERROR] Not a valid class: ‹error› //│ Type: ⊥ @@ -34,20 +35,20 @@ fun Oops() = 1 Oops().Oops#a() //│ ╔══[ERROR] Identifier `Oops` does not name a known class symbol. -//│ ║ l.35: Oops().Oops#a() +//│ ║ l.36: Oops().Oops#a() //│ ╙── ^^^^^ //│ ╔══[ERROR] Not a valid class: reference -//│ ║ l.35: Oops().Oops#a() +//│ ║ l.36: Oops().Oops#a() //│ ╙── ^^^^^ //│ Type: ⊥ data class Oops2() (new Oops2()).Oops2#a() //│ ╔══[ERROR] Class 'Oops2' does not contain member 'a'. -//│ ║ l.45: (new Oops2()).Oops2#a() +//│ ║ l.46: (new Oops2()).Oops2#a() //│ ╙── ^ //│ ╔══[ERROR] a is not a valid member in class Oops2 -//│ ║ l.45: (new Oops2()).Oops2#a() +//│ ║ l.46: (new Oops2()).Oops2#a() //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Type: ⊥ @@ -56,7 +57,7 @@ data class Oops2() fun inc(x) = x + 1 inc("oops") //│ ╔══[ERROR] Type error in string literal with expected type 'x -//│ ║ l.57: inc("oops") +//│ ║ l.58: inc("oops") //│ ║ ^^^^^^ //│ ╟── because: cannot constrain Str <: 'x //│ ╟── because: cannot constrain Str <: 'x @@ -66,7 +67,7 @@ inc("oops") fun inc(x) = x + 1 inc as Int //│ ╔══[ERROR] Type error in reference with expected type Int -//│ ║ l.67: inc as Int +//│ ║ l.68: inc as Int //│ ║ ^^^ //│ ╙── because: cannot constrain ('x) ->{⊥} (Int) <: Int //│ Type: Int diff --git a/hkmc2/shared/src/test/mlscript/codegen/BasicTerms.mls b/hkmc2/shared/src/test/mlscript/codegen/BasicTerms.mls index ad80485e1d..a2ed080be2 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/BasicTerms.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/BasicTerms.mls @@ -49,8 +49,10 @@ print("Hi") //│ main = Assign: //│ lhs = $tmp //│ rhs = Call: -//│ fun = Select{member:print}: -//│ qual = Ref of member:Predef +//│ fun = Select{sym=term:module:Predef.print}: +//│ qual = Ref{disamb=module:Predef}: +//│ l = member:Predef +//│ disamb = S of module:Predef //│ name = Ident of "print" //│ args = Ls of //│ Arg: diff --git a/hkmc2/shared/src/test/mlscript/codegen/ClassInClass.mls b/hkmc2/shared/src/test/mlscript/codegen/ClassInClass.mls index e81205fe02..195b55a49a 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ClassInClass.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ClassInClass.mls @@ -64,7 +64,7 @@ data class Outer(a, b) with //│ o2(c, d) { //│ let tmp; //│ tmp = this.Inner(c); -//│ return runtime.safeCall(tmp.i1(d)) +//│ return tmp.i1(d) //│ } //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "Outer", ["a", "b"]]; diff --git a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls index 702afdc8d7..2736df02d3 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/FieldSymbols.mls @@ -104,29 +104,39 @@ case //│ modulefulness = Modulefulness of N //│ restParam = N //│ body = Match: -//│ scrut = Ref of caseScrut +//│ scrut = Ref: +//│ l = caseScrut +//│ disamb = N //│ arms = Ls of //│ Tuple2: //│ _1 = Cls: //│ cls = class:Foo -//│ path = Select{class:Foo}: -//│ qual = Ref of member:Foo -//│ name = Ident of "class" +//│ path = Ref{disamb=class:Foo}: +//│ l = member:Foo +//│ disamb = S of class:Foo //│ _2 = Assign: //│ lhs = $param0 -//│ rhs = Select{class:Foo.x}: -//│ qual = Ref of caseScrut +//│ rhs = Select{sym=term:class:Foo.x}: +//│ qual = Ref: +//│ l = caseScrut +//│ disamb = N //│ name = Ident of "x" //│ rest = Assign: \ //│ lhs = a -//│ rhs = Ref of $param0 +//│ rhs = Ref: +//│ l = $param0 +//│ disamb = N //│ rest = Return: \ -//│ res = Ref of a +//│ res = Ref: +//│ l = a +//│ disamb = N //│ implct = false //│ dflt = S of Throw of Instantiate: //│ mut = false //│ cls = Select: -//│ qual = Ref of globalThis:globalThis +//│ qual = Ref{disamb=globalThis:globalThis}: +//│ l = globalThis:globalThis +//│ disamb = S of globalThis:globalThis //│ name = Ident of "Error" //│ args = Ls of //│ Arg: @@ -135,7 +145,9 @@ case //│ rest = End of "" //│ rest = Assign: \ //│ lhs = $block$res -//│ rhs = Ref of member:lambda +//│ rhs = Ref: +//│ l = member:lambda +//│ disamb = N //│ rest = Return: \ //│ res = Lit of UnitLit of false //│ implct = true diff --git a/hkmc2/shared/src/test/mlscript/codegen/ParamClasses.mls b/hkmc2/shared/src/test/mlscript/codegen/ParamClasses.mls index 29994014fb..30be3cf8a8 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ParamClasses.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ParamClasses.mls @@ -233,9 +233,15 @@ Foo(10, 20, 30, 40, 50) //│ = Foo(_, 20, _, 40, _) -:todo // * This should be an error :e class Foo(val z, val z) +//│ ╔══[ERROR] Duplicate definition of member named 'z'. +//│ ╟── Defined at: +//│ ║ l.237: class Foo(val z, val z) +//│ ║ ^ +//│ ╟── Defined at: +//│ ║ l.237: class Foo(val z, val z) +//│ ╙── ^ //│ JS (unsanitized): //│ let Foo9; //│ Foo9 = function Foo(z, z1) { @@ -245,10 +251,7 @@ class Foo(val z, val z) //│ static { //│ Foo9.class = this //│ } -//│ constructor(z, z1) { -//│ this.z = z; -//│ this.z = z1; -//│ } +//│ constructor(z, z1) {} //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "Foo", ["z", "z"]]; //│ }); @@ -256,6 +259,6 @@ class Foo(val z, val z) Foo(1, 2) //│ JS (unsanitized): //│ Foo9(1, 2) -//│ = Foo(2, 2) +//│ = Foo(undefined, undefined) diff --git a/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls b/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls index cfec5a3a72..563e55711b 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/PlainClasses.mls @@ -46,7 +46,7 @@ Foo :re Foo() //│ JS (unsanitized): -//│ Foo1() +//│ runtime.safeCall(Foo1()) //│ ═══[RUNTIME ERROR] TypeError: Class constructor Foo cannot be invoked without 'new' diff --git a/hkmc2/shared/src/test/mlscript/codegen/SanityChecks.mls b/hkmc2/shared/src/test/mlscript/codegen/SanityChecks.mls index efd52746db..d5ef1fbb25 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/SanityChecks.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/SanityChecks.mls @@ -1,5 +1,6 @@ :js +// * In this test, we use `id` to wrap functions so that compile-time arity checks get bypassed. :ssjs @@ -20,36 +21,29 @@ f(2, 3) :expect NaN :ssjs :noSanityCheck -:e fun f2(x, y) = x + y -f2(2) -//│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.25: f2(2) -//│ ╙── ^^^ +id(f2)(2) //│ JS: -//│ f2 = function f2(x, y) { return x + y }; block$res2 = f2(2); undefined +//│ f2 = function f2(x, y) { +//│ return x + y +//│ }; +//│ tmp = Predef.id(f2); +//│ block$res2 = runtime.safeCall(tmp(2)); +//│ undefined //│ = NaN :ssjs :re -:e -f(2) -//│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.36: f(2) -//│ ╙── ^^^ +id(f)(2) //│ JS: -//│ block$res3 = runtime.checkCall(f(2)); undefined +//│ tmp1 = runtime.checkCall(Predef.id(f)); block$res3 = runtime.safeCall(tmp1(2)); undefined //│ ═══[RUNTIME ERROR] Error: Function 'f' expected 2 arguments but got 1 :ssjs :re -:e fun f(x)(y, z) = x + y + z -f(3)(4) -//│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.49: f(3)(4) -//│ ╙── ^^^ +id(f)(3)(4) //│ JS: //│ f1 = function f(...args) { //│ runtime.checkArgs("f", 1, true, args.length); @@ -58,13 +52,14 @@ f(3)(4) //│ runtime.checkArgs("", 2, true, args1.length); //│ let y = args1[0]; //│ let z = args1[1]; -//│ let tmp1; -//│ tmp1 = x + y; -//│ return tmp1 + z +//│ let tmp4; +//│ tmp4 = x + y; +//│ return tmp4 + z //│ } //│ }; -//│ tmp = runtime.checkCall(f1(3)); -//│ block$res4 = runtime.safeCall(tmp(4)); +//│ tmp2 = runtime.checkCall(Predef.id(f1)); +//│ tmp3 = runtime.safeCall(tmp2(3)); +//│ block$res4 = runtime.safeCall(tmp3(4)); //│ undefined //│ ═══[RUNTIME ERROR] Error: Function expected 2 arguments but got 1 @@ -100,7 +95,7 @@ f(2) :noSanityCheck data class Cls(x, y) with fun f(z, p) = x + y + z + p -Cls(1, 2).f(3) +id(Cls(1, 2)).f(3) //│ JS: //│ Cls1 = function Cls(x, y) { //│ return globalThis.Object.freeze(new Cls.class(x, y)); @@ -114,16 +109,17 @@ Cls(1, 2).f(3) //│ this.y = y; //│ } //│ f(z, p) { -//│ let tmp2, tmp3; -//│ tmp2 = this.x + this.y; -//│ tmp3 = tmp2 + z; -//│ return tmp3 + p +//│ let tmp6, tmp7; +//│ tmp6 = this.x + this.y; +//│ tmp7 = tmp6 + z; +//│ return tmp7 + p //│ } //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "Cls", ["x", "y"]]; //│ }); -//│ tmp1 = Cls1(1, 2); -//│ block$res7 = runtime.safeCall(tmp1.f(3)); +//│ tmp4 = Cls1(1, 2); +//│ tmp5 = Predef.id(tmp4); +//│ block$res7 = runtime.safeCall(tmp5.f(3)); //│ undefined //│ = NaN @@ -131,7 +127,7 @@ Cls(1, 2).f(3) :re data class Cls(x, y) with fun f(z, p) = x + y + z + p -Cls(1, 2).f(3) +id(Cls(1, 2)).f(3) //│ JS: //│ Cls3 = function Cls(...args) { //│ return globalThis.Object.freeze(new Cls.class(...args)); @@ -149,16 +145,17 @@ Cls(1, 2).f(3) //│ runtime.checkArgs("f", 2, true, args.length); //│ let z = args[0]; //│ let p = args[1]; -//│ let tmp3, tmp4; -//│ tmp3 = this.x + this.y; -//│ tmp4 = tmp3 + z; -//│ return tmp4 + p +//│ let tmp8, tmp9; +//│ tmp8 = this.x + this.y; +//│ tmp9 = tmp8 + z; +//│ return tmp9 + p //│ } //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "Cls", ["x", "y"]]; //│ }); -//│ tmp2 = runtime.checkCall(Cls3(1, 2)); -//│ block$res8 = runtime.safeCall(tmp2.f(3)); +//│ tmp6 = runtime.checkCall(Cls3(1, 2)); +//│ tmp7 = runtime.checkCall(Predef.id(tmp6)); +//│ block$res8 = runtime.safeCall(tmp7.f(3)); //│ undefined //│ ═══[RUNTIME ERROR] Error: Function 'f' expected 2 arguments but got 1 @@ -167,7 +164,7 @@ Cls(1, 2).f(3) :re data class Cls(x, y) with fun f(z, p)(q, s) = x + y + z + p + q + s -Cls(1, 2).f(3, 4)(5) +id(Cls(1, 2)).f(3, 4)(5) //│ JS: //│ Cls5 = function Cls(...args) { //│ return globalThis.Object.freeze(new Cls.class(...args)); @@ -189,20 +186,21 @@ Cls(1, 2).f(3, 4)(5) //│ runtime.checkArgs("", 2, true, args1.length); //│ let q = args1[0]; //│ let s = args1[1]; -//│ let tmp5, tmp6, tmp7, tmp8; -//│ tmp5 = this.x + this.y; -//│ tmp6 = tmp5 + z; -//│ tmp7 = tmp6 + p; -//│ tmp8 = tmp7 + q; -//│ return tmp8 + s +//│ let tmp11, tmp12, tmp13, tmp14; +//│ tmp11 = this.x + this.y; +//│ tmp12 = tmp11 + z; +//│ tmp13 = tmp12 + p; +//│ tmp14 = tmp13 + q; +//│ return tmp14 + s //│ } //│ } //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "Cls", ["x", "y"]]; //│ }); -//│ tmp3 = runtime.checkCall(Cls5(1, 2)); -//│ tmp4 = tmp3.f(3, 4); -//│ block$res9 = runtime.safeCall(tmp4(5)); +//│ tmp8 = runtime.checkCall(Cls5(1, 2)); +//│ tmp9 = runtime.checkCall(Predef.id(tmp8)); +//│ tmp10 = tmp9.f(3, 4); +//│ block$res9 = runtime.safeCall(tmp10(5)); //│ undefined //│ ═══[RUNTIME ERROR] Error: Function expected 2 arguments but got 1 @@ -211,6 +209,7 @@ Cls(1, 2).f(3, 4)(5) console.log(1) //│ JS: //│ selRes = globalThis.console; +//│ discarded = globalThis.console$__checkNotMethod; //│ if (selRes === undefined) { //│ throw globalThis.Object.freeze(new globalThis.Error("Access to required field 'console' yielded 'undefined'")) //│ } @@ -224,7 +223,7 @@ console.log(1) globalThis.x //│ JS: //│ selRes1 = globalThis.x; -//│ discarded = globalThis.x$__checkNotMethod; +//│ discarded1 = globalThis.x$__checkNotMethod; //│ if (selRes1 === undefined) { //│ throw globalThis.Object.freeze(new globalThis.Error("Access to required field 'x' yielded 'undefined'")) //│ } @@ -282,9 +281,9 @@ if M.A(1).y is //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "M"]; //│ }); -//│ tmp5 = runtime.checkCall(M1.A(1)); -//│ selRes2 = tmp5.y; -//│ discarded1 = tmp5.y$__checkNotMethod; +//│ tmp11 = runtime.checkCall(M1.A(1)); +//│ selRes2 = tmp11.y; +//│ discarded2 = tmp11.y$__checkNotMethod; //│ if (selRes2 === undefined) { //│ throw globalThis.Object.freeze(new globalThis.Error("Access to required field 'y' yielded 'undefined'")) //│ } @@ -302,12 +301,13 @@ M.A(1).y console.log() //│ JS: //│ selRes3 = globalThis.console; +//│ discarded3 = globalThis.console$__checkNotMethod; //│ if (selRes3 === undefined) { //│ throw globalThis.Object.freeze(new globalThis.Error("Access to required field 'console' yielded 'undefined'")) //│ } -//│ tmp6 = runtime.checkCall(M1.A(1)); -//│ selRes4 = tmp6.y; -//│ discarded2 = tmp6.y$__checkNotMethod; +//│ tmp12 = runtime.checkCall(M1.A(1)); +//│ selRes4 = tmp12.y; +//│ discarded4 = tmp12.y$__checkNotMethod; //│ if (selRes4 === undefined) { //│ throw globalThis.Object.freeze(new globalThis.Error("Access to required field 'y' yielded 'undefined'")) //│ } @@ -322,7 +322,7 @@ M.A(1).y M.A(1).y console.log() //│ JS: -//│ tmp7 = M1.A(1); block$res15 = runtime.safeCall(globalThis.console.log(tmp7.y)); undefined +//│ tmp13 = M1.A(1); block$res15 = runtime.safeCall(globalThis.console.log(tmp13.y)); undefined //│ > undefined :noSanityCheck @@ -338,15 +338,15 @@ M.A(2).y > 1 :ssjs M.A(1).g(0) //│ JS: -//│ tmp10 = runtime.checkCall(M1.A(1)); block$res18 = runtime.safeCall(tmp10.g(0)); undefined -//│ ═══[RUNTIME ERROR] TypeError: tmp10.g is not a function +//│ tmp16 = runtime.checkCall(M1.A(1)); block$res18 = runtime.safeCall(tmp16.g(0)); undefined +//│ ═══[RUNTIME ERROR] TypeError: tmp16.g is not a function :ssjs M.A(1).f(0) //│ JS: -//│ tmp11 = runtime.checkCall(M1.A(1)); block$res19 = runtime.safeCall(tmp11.f(0)); undefined +//│ tmp17 = runtime.checkCall(M1.A(1)); block$res19 = runtime.checkCall(tmp17.f(0)); undefined //│ = 1 diff --git a/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls b/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls index 3f48d6c062..99166a71c4 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/ThisCallVariations.mls @@ -53,9 +53,17 @@ id(Example) .!. oops(2) //│ = [2, 1] +:e data class Example2(val a) with val a = 1 fun f(inc) = Example2(a + inc) +//│ ╔══[ERROR] Duplicate definition of member named 'a'. +//│ ╟── Defined at: +//│ ║ l.57: data class Example2(val a) with +//│ ║ ^ +//│ ╟── Defined at: +//│ ║ l.58: val a = 1 +//│ ╙── ^^^^^^^^^ let oops2 = Example2(0).("f") //│ oops2 = fun f diff --git a/hkmc2/shared/src/test/mlscript/ctx/MissingDefinitions2.mls b/hkmc2/shared/src/test/mlscript/ctx/MissingDefinitions2.mls index 468e4a22cd..2572b03c45 100644 --- a/hkmc2/shared/src/test/mlscript/ctx/MissingDefinitions2.mls +++ b/hkmc2/shared/src/test/mlscript/ctx/MissingDefinitions2.mls @@ -74,7 +74,7 @@ test(1, 2) //│ ║ l.55: fun (++) test: (Int, Int) -> Int //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ JS (unsanitized): -//│ let tmp2; tmp2 = test(); runtime.safeCall(tmp2(1, 1)) +//│ let tmp2; tmp2 = test(); tmp2(1, 1) //│ ═══[RUNTIME ERROR] ReferenceError: test is not defined diff --git a/hkmc2/shared/src/test/mlscript/ctx/SymbolResolution.mls b/hkmc2/shared/src/test/mlscript/ctx/SymbolResolution.mls index 4fcca7c686..59d45edb93 100644 --- a/hkmc2/shared/src/test/mlscript/ctx/SymbolResolution.mls +++ b/hkmc2/shared/src/test/mlscript/ctx/SymbolResolution.mls @@ -24,34 +24,50 @@ M.foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:foo,typ=module:M}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M -//│ nme = Ident of "foo" +//│ res = Resolved{sym=term:module:M.foo,typ=module:M}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "foo" +//│ sym = term:module:M.foo M.bar //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:bar,typ=module:M}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M -//│ nme = Ident of "bar" +//│ res = Resolved{sym=term:module:M.bar,typ=module:M}: +//│ t = Sel{sym=member:bar}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "bar" +//│ sym = term:module:M.bar M.baz //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:baz}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M -//│ nme = Ident of "baz" +//│ res = Resolved{sym=term:module:M.baz}: +//│ t = Sel{sym=member:baz}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "baz" +//│ sym = term:module:M.baz M.baz() //│ Resolved tree: //│ Blk: //│ stats = Nil //│ res = App{typ=module:M}: -//│ lhs = Sel{sym=member:baz}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M -//│ nme = Ident of "baz" +//│ lhs = Resolved{sym=term:module:M.baz}: +//│ t = Sel{sym=member:baz}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "baz" +//│ sym = term:module:M.baz //│ rhs = Tup of Nil M.foo.bar.baz() @@ -59,59 +75,79 @@ M.foo.bar.baz() //│ Blk: //│ stats = Nil //│ res = App{typ=module:M}: -//│ lhs = Sel{sym=member:baz}: -//│ prefix = Sel{sym=member:bar,typ=module:M}: -//│ prefix = Sel{sym=member:foo,typ=module:M}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M -//│ nme = Ident of "foo" -//│ nme = Ident of "bar" -//│ nme = Ident of "baz" +//│ lhs = Resolved{sym=term:module:M.baz}: +//│ t = Sel{sym=member:baz}: +//│ prefix = Sel{sym=member:bar,typ=module:M}: +//│ prefix = Sel{sym=member:foo,typ=module:M}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "foo" +//│ nme = Ident of "bar" +//│ nme = Ident of "baz" +//│ sym = term:module:M.baz //│ rhs = Tup of Nil M.that.that //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:that,typ=module:M}: -//│ prefix = Sel{sym=member:that,typ=module:N}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M +//│ res = Resolved{sym=term:module:N.that,typ=module:M}: +//│ t = Sel{sym=member:that}: +//│ prefix = Sel{sym=member:that,typ=module:N}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "that" //│ nme = Ident of "that" -//│ nme = Ident of "that" +//│ sym = term:module:N.that M.that.that.that.that.that.that //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:that,typ=module:M}: -//│ prefix = Sel{sym=member:that,typ=module:N}: -//│ prefix = Sel{sym=member:that,typ=module:M}: -//│ prefix = Sel{sym=member:that,typ=module:N}: -//│ prefix = Sel{sym=member:that,typ=module:M}: -//│ prefix = Sel{sym=member:that,typ=module:N}: -//│ prefix = Ref{sym=member:M,typ=module:M} of member:M +//│ res = Resolved{sym=term:module:N.that,typ=module:M}: +//│ t = Sel{sym=member:that}: +//│ prefix = Sel{sym=member:that,typ=module:N}: +//│ prefix = Sel{sym=member:that,typ=module:M}: +//│ prefix = Sel{sym=member:that,typ=module:N}: +//│ prefix = Sel{sym=member:that,typ=module:M}: +//│ prefix = Sel{sym=member:that,typ=module:N}: +//│ prefix = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M +//│ nme = Ident of "that" //│ nme = Ident of "that" //│ nme = Ident of "that" //│ nme = Ident of "that" //│ nme = Ident of "that" //│ nme = Ident of "that" -//│ nme = Ident of "that" +//│ sym = term:module:N.that R.foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel{sym=member:foo}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "foo" +//│ res = Resolved{sym=term:module:R.foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "foo" +//│ sym = term:module:R.foo R.foo() //│ Resolved tree: //│ Blk: //│ stats = Nil //│ res = App: -//│ lhs = Sel{sym=member:foo}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "foo" +//│ lhs = Resolved{sym=term:module:R.foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "foo" +//│ sym = term:module:R.foo //│ rhs = Tup of Nil R.foo()() @@ -120,9 +156,13 @@ R.foo()() //│ stats = Nil //│ res = App{typ=module:N}: //│ lhs = App: -//│ lhs = Sel{sym=member:foo}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "foo" +//│ lhs = Resolved{sym=term:module:R.foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "foo" +//│ sym = term:module:R.foo //│ rhs = Tup of Nil //│ rhs = Tup of Nil @@ -133,9 +173,13 @@ R.foo()()() //│ res = App: //│ lhs = App{typ=module:N}: //│ lhs = App: -//│ lhs = Sel{sym=member:foo}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "foo" +//│ lhs = Resolved{sym=term:module:R.foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "foo" +//│ sym = term:module:R.foo //│ rhs = Tup of Nil //│ rhs = Tup of Nil //│ rhs = Tup of Nil @@ -151,23 +195,33 @@ R.bar //│ res = App{typ=module:M}: //│ lhs = App: //│ lhs = App: -//│ lhs = Sel{sym=member:bar}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "bar" +//│ lhs = Resolved{sym=term:module:R.bar}: +//│ t = Sel{sym=member:bar}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "bar" +//│ sym = term:module:R.bar //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Int),typ=class:Int} of member:instance$Ident(Int) +//│ term = Resolved{sym=term:instance$Ident(Int),typ=class:Int}: +//│ t = Ref{sym=member:instance$Ident(Int)} of member:instance$Ident(Int) +//│ sym = term:instance$Ident(Int) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Num),typ=class:Num} of member:instance$Ident(Num) +//│ term = Resolved{sym=term:instance$Ident(Num),typ=class:Num}: +//│ t = Ref{sym=member:instance$Ident(Num)} of member:instance$Ident(Num) +//│ sym = term:instance$Ident(Num) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Str),typ=class:Str} of member:instance$Ident(Str) +//│ term = Resolved{sym=term:instance$Ident(Str),typ=class:Str}: +//│ t = Ref{sym=member:instance$Ident(Str)} of member:instance$Ident(Str) +//│ sym = term:instance$Ident(Str) //│ asc = N // the symbol of this Ref should be M because of the implicit application @@ -178,21 +232,29 @@ foo //│ res = App{typ=module:M}: //│ lhs = App: //│ lhs = App: -//│ lhs = Ref{sym=member:foo} of member:foo +//│ lhs = Resolved{sym=term:foo}: +//│ t = Ref{sym=member:foo} of member:foo +//│ sym = term:foo //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Int),typ=class:Int} of member:instance$Ident(Int) +//│ term = Resolved{sym=term:instance$Ident(Int),typ=class:Int}: +//│ t = Ref{sym=member:instance$Ident(Int)} of member:instance$Ident(Int) +//│ sym = term:instance$Ident(Int) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Num),typ=class:Num} of member:instance$Ident(Num) +//│ term = Resolved{sym=term:instance$Ident(Num),typ=class:Num}: +//│ t = Ref{sym=member:instance$Ident(Num)} of member:instance$Ident(Num) +//│ sym = term:instance$Ident(Num) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Str),typ=class:Str} of member:instance$Ident(Str) +//│ term = Resolved{sym=term:instance$Ident(Str),typ=class:Str}: +//│ t = Ref{sym=member:instance$Ident(Str)} of member:instance$Ident(Str) +//│ sym = term:instance$Ident(Str) //│ asc = N // the symbol of this TyApp should be M because of the implicit application @@ -204,26 +266,38 @@ R.bar[Int] //│ res = App{typ=module:M}: //│ lhs = App: //│ lhs = App: -//│ lhs = TyApp{sym=member:bar}: -//│ lhs = Sel{sym=member:bar}: -//│ prefix = Ref{sym=member:R,typ=module:R} of member:R -//│ nme = Ident of "bar" +//│ lhs = TyApp{sym=term:module:R.bar}: +//│ lhs = Resolved{sym=term:module:R.bar}: +//│ t = Sel{sym=member:bar}: +//│ prefix = Resolved{sym=module:R,typ=module:R}: +//│ t = Ref{sym=member:R} of member:R +//│ sym = module:R +//│ nme = Ident of "bar" +//│ sym = term:module:R.bar //│ targs = Ls of -//│ Ref{sym=member:Int} of member:Int +//│ Resolved{sym=class:Int}: +//│ t = Ref{sym=member:Int} of member:Int +//│ sym = class:Int //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Int),typ=class:Int} of member:instance$Ident(Int) +//│ term = Resolved{sym=term:instance$Ident(Int),typ=class:Int}: +//│ t = Ref{sym=member:instance$Ident(Int)} of member:instance$Ident(Int) +//│ sym = term:instance$Ident(Int) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Num),typ=class:Num} of member:instance$Ident(Num) +//│ term = Resolved{sym=term:instance$Ident(Num),typ=class:Num}: +//│ t = Ref{sym=member:instance$Ident(Num)} of member:instance$Ident(Num) +//│ sym = term:instance$Ident(Num) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Str),typ=class:Str} of member:instance$Ident(Str) +//│ term = Resolved{sym=term:instance$Ident(Str),typ=class:Str}: +//│ t = Ref{sym=member:instance$Ident(Str)} of member:instance$Ident(Str) +//│ sym = term:instance$Ident(Str) //│ asc = N // the symbol of this TyApp should be M because of the implicit application @@ -235,22 +309,32 @@ foo[Int] //│ res = App{typ=module:M}: //│ lhs = App: //│ lhs = App: -//│ lhs = TyApp{sym=member:foo}: -//│ lhs = Ref{sym=member:foo} of member:foo +//│ lhs = TyApp{sym=term:foo}: +//│ lhs = Resolved{sym=term:foo}: +//│ t = Ref{sym=member:foo} of member:foo +//│ sym = term:foo //│ targs = Ls of -//│ Ref{sym=member:Int} of member:Int +//│ Resolved{sym=class:Int}: +//│ t = Ref{sym=member:Int} of member:Int +//│ sym = class:Int //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Int),typ=class:Int} of member:instance$Ident(Int) +//│ term = Resolved{sym=term:instance$Ident(Int),typ=class:Int}: +//│ t = Ref{sym=member:instance$Ident(Int)} of member:instance$Ident(Int) +//│ sym = term:instance$Ident(Int) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Num),typ=class:Num} of member:instance$Ident(Num) +//│ term = Resolved{sym=term:instance$Ident(Num),typ=class:Num}: +//│ t = Ref{sym=member:instance$Ident(Num)} of member:instance$Ident(Num) +//│ sym = term:instance$Ident(Num) //│ asc = N //│ rhs = Tup of Ls of //│ Fld: //│ flags = () -//│ term = Ref{sym=member:instance$Ident(Str),typ=class:Str} of member:instance$Ident(Str) +//│ term = Resolved{sym=term:instance$Ident(Str),typ=class:Str}: +//│ t = Ref{sym=member:instance$Ident(Str)} of member:instance$Ident(Str) +//│ sym = term:instance$Ident(Str) //│ asc = N diff --git a/hkmc2/shared/src/test/mlscript/ctx/TypeResolution.mls b/hkmc2/shared/src/test/mlscript/ctx/TypeResolution.mls index fbba32ad5b..887bd29387 100644 --- a/hkmc2/shared/src/test/mlscript/ctx/TypeResolution.mls +++ b/hkmc2/shared/src/test/mlscript/ctx/TypeResolution.mls @@ -2,14 +2,15 @@ class Foo with val foo: Foo = new Foo -// * TODO: new-expression should also be resolvable for its type :rt new Foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = New: -//│ cls = Ref{sym=member:Foo} of member:Foo +//│ res = New{typ=class:Foo}: +//│ cls = Resolved{sym=class:Foo}: +//│ t = Ref{sym=member:Foo} of member:Foo +//│ sym = class:Foo //│ args = Nil //│ rft = N @@ -20,7 +21,9 @@ new! Foo //│ Blk: //│ stats = Nil //│ res = DynNew: -//│ cls = Ref{sym=member:Foo} of member:Foo +//│ cls = Resolved{sym=class:Foo}: +//│ t = Ref{sym=member:Foo} of member:Foo +//│ sym = class:Foo //│ args = Nil val foo: Foo = new Foo @@ -30,28 +33,33 @@ foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:foo,typ=class:Foo} of member:foo +//│ res = Resolved{sym=term:foo,typ=class:Foo}: +//│ t = Ref{sym=member:foo} of member:foo +//│ sym = term:foo :rt foo.foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel: -//│ prefix = Ref{sym=member:foo,typ=class:Foo} of member:foo -//│ nme = Ident of "foo" +//│ res = Resolved{sym=term:class:Foo.foo,typ=class:Foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Ref{sym=member:foo,typ=class:Foo} of member:foo +//│ nme = Ident of "foo" +//│ sym = term:class:Foo.foo class Foo2[A, B] with val foo: Foo2[Int, Str] = new Foo2 -// * TODO: new-expression should also be resolvable for its type :rt new Foo2 //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = New: -//│ cls = Ref{sym=member:Foo2} of member:Foo2 +//│ res = New{typ=class:Foo2}: +//│ cls = Resolved{sym=class:Foo2}: +//│ t = Ref{sym=member:Foo2} of member:Foo2 +//│ sym = class:Foo2 //│ args = Nil //│ rft = N @@ -62,7 +70,9 @@ new! Foo2 //│ Blk: //│ stats = Nil //│ res = DynNew: -//│ cls = Ref{sym=member:Foo2} of member:Foo2 +//│ cls = Resolved{sym=class:Foo2}: +//│ t = Ref{sym=member:Foo2} of member:Foo2 +//│ sym = class:Foo2 //│ args = Nil val foo: Foo2[Str, Int] = new Foo2 @@ -72,16 +82,20 @@ foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:foo,typ=class:Foo2[class:Str, class:Int]} of member:foo +//│ res = Resolved{sym=term:foo,typ=class:Foo2[class:Str, class:Int]}: +//│ t = Ref{sym=member:foo} of member:foo +//│ sym = term:foo :rt foo.foo //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Sel: -//│ prefix = Ref{sym=member:foo,typ=class:Foo2[class:Str, class:Int]} of member:foo -//│ nme = Ident of "foo" +//│ res = Resolved{sym=term:class:Foo2.foo,typ=class:Foo2[class:Int, class:Str]}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Ref{sym=member:foo,typ=class:Foo2[class:Str, class:Int]} of member:foo +//│ nme = Ident of "foo" +//│ sym = term:class:Foo2.foo :rt fun f(x: Foo) = x @@ -91,7 +105,7 @@ fun f(x: Foo) = x //│ TermDefinition: //│ k = Fun //│ sym = member:f -//│ tsym = .f +//│ tsym = term:f //│ params = Ls of //│ ParamList: //│ flags = () @@ -99,7 +113,9 @@ fun f(x: Foo) = x //│ Param: //│ flags = () //│ sym = x -//│ sign = S of Ref{sym=member:Foo} of member:Foo +//│ sign = S of Resolved{sym=class:Foo}: +//│ t = Ref{sym=member:Foo} of member:Foo +//│ sym = class:Foo //│ modulefulness = Modulefulness of N //│ restParam = N //│ tparams = N @@ -120,14 +136,18 @@ M //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:M,typ=module:M} of member:M +//│ res = Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M :rt O //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:O,typ=object:O} of member:O +//│ res = Resolved{sym=object:O,typ=object:O}: +//│ t = Ref{sym=member:O} of member:O +//│ sym = object:O val m: module M = M val o: O = O @@ -137,14 +157,18 @@ m //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:m,typ=module:M} of member:m +//│ res = Resolved{sym=term:m,typ=module:M}: +//│ t = Ref{sym=member:m} of member:m +//│ sym = term:m :rt o //│ Resolved tree: //│ Blk: //│ stats = Nil -//│ res = Ref{sym=member:o,typ=object:O} of member:o +//│ res = Resolved{sym=term:o,typ=object:O}: +//│ t = Ref{sym=member:o} of member:o +//│ sym = term:o :rt fun f(module m: M): module M = m @@ -154,7 +178,7 @@ fun f(module m: M): module M = m //│ TermDefinition: //│ k = Fun //│ sym = member:f -//│ tsym = .f +//│ tsym = term:f //│ params = Ls of //│ ParamList: //│ flags = () @@ -162,11 +186,15 @@ fun f(module m: M): module M = m //│ Param: //│ flags = () //│ sym = m -//│ sign = S of Ref{sym=member:M} of member:M +//│ sign = S of Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M //│ modulefulness = Modulefulness of S of module:M //│ restParam = N //│ tparams = N -//│ sign = S of Ref{sym=member:M} of member:M +//│ sign = S of Resolved{sym=module:M,typ=module:M}: +//│ t = Ref{sym=member:M} of member:M +//│ sym = module:M //│ body = S of Ref{sym=m,typ=module:M} of m //│ resSym = ‹result of member:f› //│ flags = () @@ -183,7 +211,7 @@ fun f(o: O) = o //│ TermDefinition: //│ k = Fun //│ sym = member:f -//│ tsym = .f +//│ tsym = term:f //│ params = Ls of //│ ParamList: //│ flags = () @@ -191,7 +219,9 @@ fun f(o: O) = o //│ Param: //│ flags = () //│ sym = o -//│ sign = S of Ref{sym=member:O} of member:O +//│ sign = S of Resolved{sym=object:O,typ=object:O}: +//│ t = Ref{sym=member:O} of member:O +//│ sym = object:O //│ modulefulness = Modulefulness of N //│ restParam = N //│ tparams = N @@ -203,3 +233,81 @@ fun f(o: O) = o //│ annotations = Nil //│ companion = N //│ res = Lit of UnitLit of false + +// The implicit `this` (class:Foo) in the SynthSel(class:Foo, "foo") should be resolved correctly. +:rt +class Foo with + val foo = 42 + foo +//│ Resolved tree: +//│ Blk: +//│ stats = Ls of +//│ Plain: +//│ owner = N +//│ kind = Cls +//│ sym = class:Foo +//│ bsym = member:Foo +//│ tparams = Nil +//│ ext = N +//│ body = ObjBody of Blk: +//│ stats = Ls of +//│ TermDefinition: +//│ k = ImmutVal +//│ sym = member:foo +//│ tsym = term:class:Foo.foo +//│ params = Nil +//│ tparams = N +//│ sign = N +//│ body = S of Lit of IntLit of 42 +//│ resSym = ‹result of member:foo› +//│ flags = (method) +//│ modulefulness = Modulefulness of N +//│ annotations = Nil +//│ companion = N +//│ res = Resolved{sym=term:class:Foo.foo}: +//│ t = SynthSel{sym=member:foo}: +//│ prefix = Ref{sym=class:Foo,typ=class:Foo} of class:Foo +//│ nme = Ident of "foo" +//│ sym = term:class:Foo.foo +//│ companion = N +//│ annotations = Nil +//│ res = Lit of UnitLit of false + +// The explicit `this` (class:Foo) in the Sel(class:Foo, "foo") should be resolved correctly. +:rt +class Foo with + val foo = 42 + this.foo +//│ Resolved tree: +//│ Blk: +//│ stats = Ls of +//│ Plain: +//│ owner = N +//│ kind = Cls +//│ sym = class:Foo +//│ bsym = member:Foo +//│ tparams = Nil +//│ ext = N +//│ body = ObjBody of Blk: +//│ stats = Ls of +//│ TermDefinition: +//│ k = ImmutVal +//│ sym = member:foo +//│ tsym = term:class:Foo.foo +//│ params = Nil +//│ tparams = N +//│ sign = N +//│ body = S of Lit of IntLit of 42 +//│ resSym = ‹result of member:foo› +//│ flags = (method) +//│ modulefulness = Modulefulness of N +//│ annotations = Nil +//│ companion = N +//│ res = Resolved{sym=term:class:Foo.foo}: +//│ t = Sel{sym=member:foo}: +//│ prefix = Ref{sym=class:Foo,typ=class:Foo} of class:Foo +//│ nme = Ident of "foo" +//│ sym = term:class:Foo.foo +//│ companion = N +//│ annotations = Nil +//│ res = Lit of UnitLit of false diff --git a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls index d6f247d0b9..5b36a10887 100644 --- a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls +++ b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls @@ -17,9 +17,9 @@ declare class Set declare class Map declare class WeakSet declare class WeakMap -declare class Error -declare class TypeError -declare class RangeError +declare class Error(info) +declare class TypeError(info) +declare class RangeError(info) declare class Date declare class ArrayBuffer diff --git a/hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls b/hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls index 6d604a7de6..ec726f6ed4 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls @@ -192,7 +192,7 @@ f().foo() //│ z = 10; //│ capture.w$capture$0 = 1000; //│ tmp6 = Bad$(false, capture); -//│ tmp7 = runtime.safeCall(tmp6.foo()); +//│ tmp7 = tmp6.foo(); //│ return Good$(false, x, y, z, capture) //│ }; //│ tmp5 = f5(); diff --git a/hkmc2/shared/src/test/mlscript/lifter/DefnsInClass.mls b/hkmc2/shared/src/test/mlscript/lifter/DefnsInClass.mls index b679dffcae..d5b4fad2c4 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/DefnsInClass.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/DefnsInClass.mls @@ -56,7 +56,7 @@ data class A(x) with //│ getA() { //│ let tmp; //│ tmp = B$(false, this, 2); -//│ return runtime.safeCall(tmp.getB()) +//│ return tmp.getB() //│ } //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "A", ["x"]]; diff --git a/hkmc2/shared/src/test/mlscript/lifter/ModulesObjects.mls b/hkmc2/shared/src/test/mlscript/lifter/ModulesObjects.mls index b27cccd164..1ab37b7a93 100644 --- a/hkmc2/shared/src/test/mlscript/lifter/ModulesObjects.mls +++ b/hkmc2/shared/src/test/mlscript/lifter/ModulesObjects.mls @@ -54,7 +54,7 @@ foo(10) //│ toString() { return runtime.render(this); } //│ static [definitionMetadata] = ["class", "M"]; //│ }); -//│ foo1 = function foo(y) { let tmp; tmp = M$(false, y); return runtime.safeCall(tmp.foo()) }; +//│ foo1 = function foo(y) { let tmp; tmp = M$(false, y); return tmp.foo() }; //│ foo1(10) diff --git a/hkmc2/shared/src/test/mlscript/llir/Split.mls b/hkmc2/shared/src/test/mlscript/llir/Split.mls index 2e2d5cf54b..c39dbafff0 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Split.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Split.mls @@ -22,7 +22,7 @@ fun fold(acc, it) = if done(it) then acc else fold(n + acc, it) fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) map_sum(x => x, 200) -//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref($scrut)), Arg(None,Lit(IntLit(0))))) +//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref($scrut,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation :intl @@ -50,5 +50,5 @@ fun fold(acc, iter) = if iter is if it is Done then acc else fold(f(n) + acc, Map(f, it)) fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) map_sum(x => x, 200) -//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref($scrut)), Arg(None,Lit(IntLit(0))))) +//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref($scrut,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 6e80c9547e..9c5838e9bc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -10,5 +10,5 @@ fun mkTup(x, y) = [x, y] fun fst(t) = if t is [x, y] then x mkTup(1, 2) //│ = [1, 2] -//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(t)), Arg(None,Lit(IntLit(0))))) +//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(t,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls index b1c0deab22..422b1b5b83 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -3,7 +3,7 @@ :import NofibPrelude.mls //│ Imported 104 member(s) -//│ Error: hkmc2.ErrorReport: Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(t1)), Arg(None,Lit(IntLit(0))))) +//│ Error: hkmc2.ErrorReport: Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(t1,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation @@ -13,7 +13,7 @@ fun dfs(r, vsns, xs) = if vsns is [vs, ns] and x :: xs and inList(x, vs) then dfs(r, [vs, ns], xs) dfs(r, [x :: vs, Nil], r(x)) is [vs', ns'] then dfs(r, [vs', (x :: ns') +: ns], xs) -//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(vsns)), Arg(None,Lit(IntLit(0))))) +//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(vsns,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation fun stronglyConnComp(es, vs) = diff --git a/hkmc2/shared/src/test/mlscript/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/nofib/scc.mls index ce3fc5f146..c54e2c4c33 100644 --- a/hkmc2/shared/src/test/mlscript/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/nofib/scc.mls @@ -12,7 +12,7 @@ fun dfs(r, vsns, xs) = if vsns is [vs, ns] and x :: xs and inList(x, vs) then dfs(r, [vs, ns], xs) dfs(r, [x :: vs, Nil], r(x)) is [vs', ns'] then dfs(r, [vs', (x :: ns') +: ns], xs) -//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(vsns)), Arg(None,Lit(IntLit(0))))) +//│ ═══[COMPILATION ERROR] Unsupported kind of Call Call(Select(Select(Ref($runtime,None),Ident(Tuple)),Ident(get)),List(Arg(None,Ref(vsns,None)), Arg(None,Lit(IntLit(0))))) //│ Stopped due to an error during the Llir generation fun stronglyConnComp(es, vs) = diff --git a/hkmc2/shared/src/test/mlscript/parser/Handler.mls b/hkmc2/shared/src/test/mlscript/parser/Handler.mls index fcca72c7ae..624ea76716 100644 --- a/hkmc2/shared/src/test/mlscript/parser/Handler.mls +++ b/hkmc2/shared/src/test/mlscript/parser/Handler.mls @@ -50,7 +50,7 @@ handle h = Eff with fun f()(r) = r(0) in foo(h) -//│ Elab: { handle h = Ref(member:Eff)() List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } +//│ Elab: { handle h = Ref(member:Eff)() List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,term:class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } :e ( @@ -74,7 +74,7 @@ handle h = Mod.Eff(3) with fun f()(r) = r(0) fun g(a)()()(r) = r(1) foo(h) -//│ Elab: { handle h = Sel(Ref(member:Mod),Ident(Eff))(Lit(IntLit(3))) List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None)), HandlerTermDefinition(r,TermDefinition(Fun,member:g,class:Handler$h$.g,List(ParamList(‹›,List(Param(‹›,a,None,Modulefulness(None))),None), ParamList(‹›,List(),None), ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))),‹result of member:g›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } +//│ Elab: { handle h = Sel(Ref(member:Mod),Ident(Eff))(Lit(IntLit(3))) List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,term:class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None)), HandlerTermDefinition(r,TermDefinition(Fun,member:g,term:class:Handler$h$.g,List(ParamList(‹›,List(Param(‹›,a,None,Modulefulness(None))),None), ParamList(‹›,List(),None), ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))),‹result of member:g›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } :e handle h = Eff with @@ -86,7 +86,7 @@ handle h = Eff with foo(h) //│ ╔══[ERROR] Only function definitions are allowed in handler blocks //│ ║ l.83: val x = 24 -//│ ╙── ^^ +//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Only function definitions are allowed in handler blocks //│ ║ l.85: fun x() = x //│ ╙── ^ @@ -104,16 +104,16 @@ handle h = Eff with foo(h) //│ ╔══[ERROR] Handler function is missing resumption parameter //│ ║ l.99: fun f = r(0) -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Handler function is missing resumption parameter //│ ║ l.100: fun g() = r(0) -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] Handler function is missing resumption parameter //│ ║ l.101: fun h()() = r(1) -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Handler function is missing resumption parameter //│ ║ l.102: fun h2()(a, b) = r(1) -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Name not found: h //│ ║ l.103: foo(h) //│ ╙── ^ @@ -128,4 +128,4 @@ foo(h) //│ ╔══[WARNING] Terms in handler block do nothing //│ ║ l.126: 12345 //│ ╙── ^^^^^ -//│ Elab: { handle h = Ref(member:Eff)() List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None)), HandlerTermDefinition(r,TermDefinition(Fun,member:g,class:Handler$h$.g,List(ParamList(‹›,List(Param(‹›,a,None,Modulefulness(None))),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))),‹result of member:g›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } +//│ Elab: { handle h = Ref(member:Eff)() List(HandlerTermDefinition(r,TermDefinition(Fun,member:f,term:class:Handler$h$.f,List(ParamList(‹›,List(),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(0)),None))))),‹result of member:f›,‹method ›,Modulefulness(None),List(),None)), HandlerTermDefinition(r,TermDefinition(Fun,member:g,term:class:Handler$h$.g,List(ParamList(‹›,List(Param(‹›,a,None,Modulefulness(None))),None)),None,None,Some(App(Ref(r),Tup(List(Fld(‹›,Lit(IntLit(1)),None))))),‹result of member:g›,‹method ›,Modulefulness(None),List(),None))) in App(Ref(member:foo),Tup(List(Fld(‹›,Ref(h),None)))) } diff --git a/hkmc2/shared/src/test/mlscript/ucs/future/SymbolicClass.mls b/hkmc2/shared/src/test/mlscript/ucs/future/SymbolicClass.mls index 13eabfbf6d..3883902479 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/future/SymbolicClass.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/future/SymbolicClass.mls @@ -42,7 +42,7 @@ new 1 :: 2 :re :sjs new (1 :: 2) -//│ ╔══[ERROR] Expected a statically known class; found application. +//│ ╔══[ERROR] Expected a statically known class; found application of type Cons. //│ ║ l.44: new (1 :: 2) //│ ║ ^^^^^^ //│ ╙── The 'new' keyword requires a statically known class; use the 'new!' operator for dynamic instantiation. diff --git a/hkmc2/shared/src/test/mlscript/ucs/hygiene/HygienicBindings.mls b/hkmc2/shared/src/test/mlscript/ucs/hygiene/HygienicBindings.mls index 7de8d4ff67..e3b652f8a8 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/hygiene/HygienicBindings.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/hygiene/HygienicBindings.mls @@ -40,16 +40,16 @@ fun h1(a) = a is None then 0 //│ Normalized: //│ > if -//│ > a is Option.Some.class(param0) and +//│ > a is Option.Some(param0) and //│ > let x = $param0 -//│ > x is Left.class(param0) and +//│ > x is Left(param0) and //│ > let y = $param0 //│ > else y //│ > let y = $param0 -//│ > y is Right.class(param0) and +//│ > y is Right(param0) and //│ > let z = $param0 //│ > else z -//│ > a is Option.None.class then 0 +//│ > a is Option.None then 0 h1(Some(Left(42))) //│ = 42 @@ -72,18 +72,18 @@ fun h2(a) = a is None then 0 //│ Normalized: //│ > if -//│ > a is Option.Some.class(param0) and +//│ > a is Option.Some(param0) and //│ > let x = $param0 //│ > let x' = x -//│ > x' is Left.class(param0) and +//│ > x' is Left(param0) and //│ > let y = $param0 //│ > else y //│ > let y = $param0 //│ > let y' = y -//│ > y' is Right.class(param0) and +//│ > y' is Right(param0) and //│ > let z = $param0 //│ > else z -//│ > a is Option.None.class then 0 +//│ > a is Option.None then 0 // :w fun h3(x, y, f, p) = diff --git a/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls b/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls index 26ad26d50c..6b42b6676e 100644 --- a/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls +++ b/hkmc2/shared/src/test/mlscript/ucs/normalization/OverlapOfPrimitives.mls @@ -151,7 +151,7 @@ fun f(arg) = if arg is Object then String(arg) //│ Normalized: //│ > if -//│ > arg is Foo.class then "just Foo" +//│ > arg is Foo then "just Foo" //│ > arg is Object then member:String(arg) fun f(arg) = if arg is diff --git a/hkmc2/shared/src/test/mlscript/ups/parametric/EtaConversion.mls b/hkmc2/shared/src/test/mlscript/ups/parametric/EtaConversion.mls index 6fc7d7c04b..bde9cbbdeb 100644 --- a/hkmc2/shared/src/test/mlscript/ups/parametric/EtaConversion.mls +++ b/hkmc2/shared/src/test/mlscript/ups/parametric/EtaConversion.mls @@ -11,9 +11,9 @@ pattern Zero = 0 //│ Normalized: //│ > if //│ > let $scrut = 0 -//│ > let $param0 = member:Zero +//│ > let $param0 = member:Zero‹pattern:Zero› //│ > let $matchResult = (member:Nullable.)unapply($param0, $scrut) -//│ > $matchResult is $runtime.MatchResult.class then true +//│ > $matchResult is ($runtime.)MatchResult‹class:MatchResult› then true //│ > else false //│ = true @@ -23,9 +23,9 @@ import "../../../mlscript-compile/Char.mls" fun foo(x) = x is Nullable(pattern Char.Letter) //│ Normalized: //│ > if -//│ > let $param0 = (member:Char.)Letter‹member:Letter› +//│ > let $param0 = (member:Char.)Letter‹pattern:Letter› //│ > let $matchResult = (member:Nullable.)unapply($param0, x) -//│ > $matchResult is $runtime.MatchResult.class then true +//│ > $matchResult is ($runtime.)MatchResult‹class:MatchResult› then true //│ > else false foo of null diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala index ceceb6f4a5..1a2b2102c9 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/JSBackendDiffMaker.scala @@ -188,7 +188,7 @@ abstract class JSBackendDiffMaker extends MLsDiffMaker: Return( Call( Value.Ref(Elaborator.State.runtimeSymbol).selSN("printRaw"), - Arg(N, Value.Ref(sym)) :: Nil)(true, false), + Arg(N, Value.Ref(sym, N)) :: Nil)(true, false), implct = true) val je = nestedScp.givenIn: jsb.block(le, endSemi = false)