From fb09e828e2a9cd1320d036e3916555b08fbde52b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 28 Nov 2018 10:05:24 +0100 Subject: [PATCH] Represent derives clauses in Template trees with implementation of their desugaring --- .../src/dotty/tools/dotc/ast/Desugar.scala | 23 +- .../dotty/tools/dotc/ast/DesugarEnums.scala | 4 +- compiler/src/dotty/tools/dotc/ast/Trees.scala | 414 +++++++++--------- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/ast/untpd.scala | 25 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../tools/dotc/parsing/JavaParsers.scala | 6 +- .../dotty/tools/dotc/parsing/Parsers.scala | 19 +- .../dotc/printing/DecompilerPrinter.scala | 2 +- .../tools/dotc/printing/RefinedPrinter.scala | 10 +- .../tools/dotc/transform/Constructors.scala | 4 +- .../tools/dotc/transform/MacroTransform.scala | 1 + .../tools/dotc/transform/MegaPhase.scala | 2 +- .../tools/dotc/transform/MoveStatics.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 38 +- .../src/dotty/tools/dotc/typer/Typer.scala | 6 +- .../src/dotty/tools/repl/ReplCompiler.scala | 5 +- .../tools/dotc/parsing/DeSugarTest.scala | 2 +- 19 files changed, 315 insertions(+), 254 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index f0221b47ad7b..5c17b164c7b4 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -297,7 +297,8 @@ object desugar { /** The expansion of a class definition. See inline comments for what is involved */ def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = { val className = checkNotReservedName(cdef).asTypeName - val impl @ Template(constr0, parents, self, _) = cdef.rhs + val impl @ Template(_, _, self, _) = cdef.rhs + val parents = impl.parents val mods = cdef.mods val companionMods = mods .withFlags((mods.flags & (AccessFlags | Final)).toCommonFlags) @@ -312,7 +313,7 @@ object desugar { meth } - val constr1 = decompose(defDef(constr0, isPrimaryConstructor = true)) + val constr1 = decompose(defDef(impl.constr, isPrimaryConstructor = true)) // The original type and value parameters in the constructor already have the flags // needed to be type members (i.e. param, and possibly also private and local unless @@ -557,12 +558,16 @@ object desugar { } def eqInstances = if (isEnum) eqInstance :: Nil else Nil + // derived type classes of non-module classes go to their companions + val (clsDerived, companionDerived) = + if (mods.is(Module)) (impl.derived, Nil) else (Nil, impl.derived) + // The thicket which is the desugared version of the companion object - // synthetic object C extends parentTpt { defs } + // synthetic object C extends parentTpt derives class-derived { defs } def companionDefs(parentTpt: Tree, defs: List[Tree]) = moduleDef( ModuleDef( - className.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs)) + className.toTermName, Template(emptyConstructor, parentTpt :: Nil, companionDerived, EmptyValDef, defs)) .withMods(companionMods | Synthetic)) .withSpan(cdef.span).toList @@ -613,10 +618,10 @@ object desugar { } companionDefs(companionParent, applyMeths ::: unapplyMeth :: companionMembers) } - else if (companionMembers.nonEmpty) + else if (companionMembers.nonEmpty || companionDerived.nonEmpty) companionDefs(anyRef, companionMembers) else if (isValueClass) { - constr0.vparamss match { + impl.constr.vparamss match { case (_ :: Nil) :: _ => companionDefs(anyRef, Nil) case _ => Nil // error will be emitted in typer } @@ -675,7 +680,7 @@ object desugar { } cpy.TypeDef(cdef: TypeDef)( name = className, - rhs = cpy.Template(impl)(constr, parents1, self1, + rhs = cpy.Template(impl)(constr, parents1, clsDerived, self1, tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths)): TypeDef } @@ -772,7 +777,7 @@ object desugar { val localType = tdef.withMods(Modifiers(Synthetic | Opaque).withPrivateWithin(tdef.name)) val companions = moduleDef(ModuleDef( - moduleName, Template(emptyConstructor, Nil, EmptyValDef, localType :: Nil)) + moduleName, Template(emptyConstructor, Nil, Nil, EmptyValDef, localType :: Nil)) .withFlags(Synthetic | Opaque)) Thicket(aliasType :: companions.toList) } @@ -1335,7 +1340,7 @@ object desugar { val (classParents, self) = if (parentCores.length == 1 && (parent.tpe eq parentCores.head)) (untpdParent :: Nil, EmptyValDef) else (parentCores map TypeTree, ValDef(nme.WILDCARD, untpdParent, EmptyTree)) - val impl = Template(emptyConstructor, classParents, self, refinements) + val impl = Template(emptyConstructor, classParents, Nil, self, refinements) TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait) } diff --git a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala index 6e280e892671..f909efff6ba3 100644 --- a/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala +++ b/compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala @@ -115,7 +115,7 @@ object DesugarEnums { val toStringDef = DefDef(nme.toString_, Nil, Nil, TypeTree(), Ident(nme.name)) .withFlags(Override) - def creator = New(Template(emptyConstructor, enumClassRef :: Nil, EmptyValDef, + def creator = New(Template(emptyConstructor, enumClassRef :: Nil, Nil, EmptyValDef, List(enumTagDef, toStringDef) ++ registerCall)) DefDef(nme.DOLLAR_NEW, Nil, List(List(param(nme.tag, defn.IntType), param(nme.name, defn.StringType))), @@ -216,7 +216,7 @@ object DesugarEnums { if (!enumClass.exists) EmptyTree else if (enumClass.typeParams.nonEmpty) { val parent = interpolatedEnumParent(span) - val impl = Template(emptyConstructor, parent :: Nil, EmptyValDef, Nil) + val impl = Template(emptyConstructor, parent :: Nil, Nil, EmptyValDef, Nil) expandEnumModule(name, impl, mods, span) } else { diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index af9415dca57d..187399bdaaf6 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -739,16 +739,24 @@ object Trees { def isClassDef: Boolean = rhs.isInstanceOf[Template[_]] } - /** extends parents { self => body } */ - case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parents: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)(implicit @constructorOnly src: SourceFile) + /** extends parents { self => body } + * @param parentsOrDerived A list of parents followed by a list of derived classes, + * if this is of class untpd.DerivingTemplate. + * Typed templates only have parents. + */ + case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parentsOrDerived: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)(implicit @constructorOnly src: SourceFile) extends DefTree[T] with WithLazyField[List[Tree[T]]] { type ThisTree[-T >: Untyped] = Template[T] def unforcedBody: LazyTreeList = unforced def unforced: LazyTreeList = preBody protected def force(x: AnyRef): Unit = preBody = x def body(implicit ctx: Context): List[Tree[T]] = forceIfLazy + + def parents: List[Tree[T]] = parentsOrDerived // overridden by DerivingTemplate + def derived: List[untpd.Tree] = Nil // overridden by DerivingTemplate } + /** import expr.selectors * where a selector is either an untyped `Ident`, `name` or * an untyped thicket consisting of `name` and `rename`. @@ -1143,9 +1151,9 @@ object Trees { case tree: TypeDef if (name == tree.name) && (rhs eq tree.rhs) => tree case _ => finalize(tree, untpd.TypeDef(name, rhs)(tree.source)) } - def Template(tree: Tree)(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList)(implicit ctx: Context): Template = tree match { - case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (self eq tree.self) && (body eq tree.unforcedBody) => tree - case _ => finalize(tree, untpd.Template(constr, parents, self, body)(tree.source)) + def Template(tree: Tree)(constr: DefDef, parents: List[Tree], derived: List[untpd.Tree], self: ValDef, body: LazyTreeList)(implicit ctx: Context): Template = tree match { + case tree: Template if (constr eq tree.constr) && (parents eq tree.parents) && (derived eq tree.derived) && (self eq tree.self) && (body eq tree.unforcedBody) => tree + case tree => finalize(tree, untpd.Template(constr, parents, derived, self, body)(tree.source)) } def Import(tree: Tree)(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import = tree match { case tree: Import if (expr eq tree.expr) && (selectors eq tree.selectors) => tree @@ -1182,8 +1190,8 @@ object Trees { DefDef(tree: Tree)(name, tparams, vparamss, tpt, rhs) def TypeDef(tree: TypeDef)(name: TypeName = tree.name, rhs: Tree = tree.rhs)(implicit ctx: Context): TypeDef = TypeDef(tree: Tree)(name, rhs) - def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(implicit ctx: Context): Template = - Template(tree: Tree)(constr, parents, self, body) + def Template(tree: Template)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody)(implicit ctx: Context): Template = + Template(tree: Tree)(constr, parents, derived, self, body) } /** Hook to indicate that a transform of some subtree should be skipped */ @@ -1206,106 +1214,106 @@ object Trees { def localCtx = if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - if (skipTransform(tree)) tree - else tree match { - case Ident(name) => - tree - case Select(qualifier, name) => - cpy.Select(tree)(transform(qualifier), name) - case This(qual) => - tree - case Super(qual, mix) => - cpy.Super(tree)(transform(qual), mix) - case Apply(fun, args) => - cpy.Apply(tree)(transform(fun), transform(args)) - case TypeApply(fun, args) => - cpy.TypeApply(tree)(transform(fun), transform(args)) - case Literal(const) => - tree - case New(tpt) => - cpy.New(tree)(transform(tpt)) - case Typed(expr, tpt) => - cpy.Typed(tree)(transform(expr), transform(tpt)) - case NamedArg(name, arg) => - cpy.NamedArg(tree)(name, transform(arg)) - case Assign(lhs, rhs) => - cpy.Assign(tree)(transform(lhs), transform(rhs)) - case Block(stats, expr) => - cpy.Block(tree)(transformStats(stats), transform(expr)) - case If(cond, thenp, elsep) => - cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) - case Closure(env, meth, tpt) => - cpy.Closure(tree)(transform(env), transform(meth), transform(tpt)) - case Match(selector, cases) => - cpy.Match(tree)(transform(selector), transformSub(cases)) - case CaseDef(pat, guard, body) => - cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) - case Labeled(bind, expr) => - cpy.Labeled(tree)(transformSub(bind), transform(expr)) - case Return(expr, from) => - cpy.Return(tree)(transform(expr), transformSub(from)) - case WhileDo(cond, body) => - cpy.WhileDo(tree)(transform(cond), transform(body)) - case Try(block, cases, finalizer) => - cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) - case SeqLiteral(elems, elemtpt) => - cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) - case Inlined(call, bindings, expansion) => - cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) - case TypeTree() => - tree - case SingletonTypeTree(ref) => - cpy.SingletonTypeTree(tree)(transform(ref)) - case AndTypeTree(left, right) => - cpy.AndTypeTree(tree)(transform(left), transform(right)) - case OrTypeTree(left, right) => - cpy.OrTypeTree(tree)(transform(left), transform(right)) - case RefinedTypeTree(tpt, refinements) => - cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) - case AppliedTypeTree(tpt, args) => - cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) - case LambdaTypeTree(tparams, body) => - implicit val ctx = localCtx - cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) - case MatchTypeTree(bound, selector, cases) => - cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) - case ByNameTypeTree(result) => - cpy.ByNameTypeTree(tree)(transform(result)) - case TypeBoundsTree(lo, hi) => - cpy.TypeBoundsTree(tree)(transform(lo), transform(hi)) - case Bind(name, body) => - cpy.Bind(tree)(name, transform(body)) - case Alternative(trees) => - cpy.Alternative(tree)(transform(trees)) - case UnApply(fun, implicits, patterns) => - cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) - case EmptyValDef => - tree - case tree @ ValDef(name, tpt, _) => - implicit val ctx = localCtx - val tpt1 = transform(tpt) - val rhs1 = transform(tree.rhs) - cpy.ValDef(tree)(name, tpt1, rhs1) - case tree @ DefDef(name, tparams, vparamss, tpt, _) => - implicit val ctx = localCtx - cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) - case tree @ TypeDef(name, rhs) => - implicit val ctx = localCtx - cpy.TypeDef(tree)(name, transform(rhs)) - case tree @ Template(constr, parents, self, _) => - cpy.Template(tree)(transformSub(constr), transform(parents), transformSub(self), transformStats(tree.body)) - case Import(expr, selectors) => - cpy.Import(tree)(transform(expr), selectors) - case PackageDef(pid, stats) => - cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(localCtx)) - case Annotated(arg, annot) => - cpy.Annotated(tree)(transform(arg), transform(annot)) - case Thicket(trees) => - val trees1 = transform(trees) - if (trees1 eq trees) tree else Thicket(trees1) - case _ => - transformMoreCases(tree) - } + if (skipTransform(tree)) tree + else tree match { + case Ident(name) => + tree + case Select(qualifier, name) => + cpy.Select(tree)(transform(qualifier), name) + case This(qual) => + tree + case Super(qual, mix) => + cpy.Super(tree)(transform(qual), mix) + case Apply(fun, args) => + cpy.Apply(tree)(transform(fun), transform(args)) + case TypeApply(fun, args) => + cpy.TypeApply(tree)(transform(fun), transform(args)) + case Literal(const) => + tree + case New(tpt) => + cpy.New(tree)(transform(tpt)) + case Typed(expr, tpt) => + cpy.Typed(tree)(transform(expr), transform(tpt)) + case NamedArg(name, arg) => + cpy.NamedArg(tree)(name, transform(arg)) + case Assign(lhs, rhs) => + cpy.Assign(tree)(transform(lhs), transform(rhs)) + case Block(stats, expr) => + cpy.Block(tree)(transformStats(stats), transform(expr)) + case If(cond, thenp, elsep) => + cpy.If(tree)(transform(cond), transform(thenp), transform(elsep)) + case Closure(env, meth, tpt) => + cpy.Closure(tree)(transform(env), transform(meth), transform(tpt)) + case Match(selector, cases) => + cpy.Match(tree)(transform(selector), transformSub(cases)) + case CaseDef(pat, guard, body) => + cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body)) + case Labeled(bind, expr) => + cpy.Labeled(tree)(transformSub(bind), transform(expr)) + case Return(expr, from) => + cpy.Return(tree)(transform(expr), transformSub(from)) + case WhileDo(cond, body) => + cpy.WhileDo(tree)(transform(cond), transform(body)) + case Try(block, cases, finalizer) => + cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) + case SeqLiteral(elems, elemtpt) => + cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) + case Inlined(call, bindings, expansion) => + cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(inlineContext(call))) + case TypeTree() => + tree + case SingletonTypeTree(ref) => + cpy.SingletonTypeTree(tree)(transform(ref)) + case AndTypeTree(left, right) => + cpy.AndTypeTree(tree)(transform(left), transform(right)) + case OrTypeTree(left, right) => + cpy.OrTypeTree(tree)(transform(left), transform(right)) + case RefinedTypeTree(tpt, refinements) => + cpy.RefinedTypeTree(tree)(transform(tpt), transformSub(refinements)) + case AppliedTypeTree(tpt, args) => + cpy.AppliedTypeTree(tree)(transform(tpt), transform(args)) + case LambdaTypeTree(tparams, body) => + implicit val ctx = localCtx + cpy.LambdaTypeTree(tree)(transformSub(tparams), transform(body)) + case MatchTypeTree(bound, selector, cases) => + cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) + case ByNameTypeTree(result) => + cpy.ByNameTypeTree(tree)(transform(result)) + case TypeBoundsTree(lo, hi) => + cpy.TypeBoundsTree(tree)(transform(lo), transform(hi)) + case Bind(name, body) => + cpy.Bind(tree)(name, transform(body)) + case Alternative(trees) => + cpy.Alternative(tree)(transform(trees)) + case UnApply(fun, implicits, patterns) => + cpy.UnApply(tree)(transform(fun), transform(implicits), transform(patterns)) + case EmptyValDef => + tree + case tree @ ValDef(name, tpt, _) => + implicit val ctx = localCtx + val tpt1 = transform(tpt) + val rhs1 = transform(tree.rhs) + cpy.ValDef(tree)(name, tpt1, rhs1) + case tree @ DefDef(name, tparams, vparamss, tpt, _) => + implicit val ctx = localCtx + cpy.DefDef(tree)(name, transformSub(tparams), vparamss mapConserve (transformSub(_)), transform(tpt), transform(tree.rhs)) + case tree @ TypeDef(name, rhs) => + implicit val ctx = localCtx + cpy.TypeDef(tree)(name, transform(rhs)) + case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => + cpy.Template(tree)(transformSub(constr), transform(tree.parents), Nil, transformSub(self), transformStats(tree.body)) + case Import(expr, selectors) => + cpy.Import(tree)(transform(expr), selectors) + case PackageDef(pid, stats) => + cpy.PackageDef(tree)(transformSub(pid), transformStats(stats)(localCtx)) + case Annotated(arg, annot) => + cpy.Annotated(tree)(transform(arg), transform(annot)) + case Thicket(trees) => + val trees1 = transform(trees) + if (trees1 eq trees) tree else Thicket(trees1) + case _ => + transformMoreCases(tree) + } } def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] = @@ -1333,102 +1341,102 @@ object Trees { foldOver(x, tree)(ctx.withSource(tree.source)) else { Stats.record(s"TreeAccumulator.foldOver/$getClass") - def localCtx = - if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx - tree match { - case Ident(name) => - x - case Select(qualifier, name) => - this(x, qualifier) - case This(qual) => - x - case Super(qual, mix) => - this(x, qual) - case Apply(fun, args) => - this(this(x, fun), args) - case TypeApply(fun, args) => - this(this(x, fun), args) - case Literal(const) => - x - case New(tpt) => - this(x, tpt) - case Typed(expr, tpt) => - this(this(x, expr), tpt) - case NamedArg(name, arg) => - this(x, arg) - case Assign(lhs, rhs) => - this(this(x, lhs), rhs) - case Block(stats, expr) => - this(this(x, stats), expr) - case If(cond, thenp, elsep) => - this(this(this(x, cond), thenp), elsep) - case Closure(env, meth, tpt) => - this(this(this(x, env), meth), tpt) - case Match(selector, cases) => - this(this(x, selector), cases) - case CaseDef(pat, guard, body) => - this(this(this(x, pat), guard), body) - case Labeled(bind, expr) => - this(this(x, bind), expr) - case Return(expr, from) => - this(this(x, expr), from) - case WhileDo(cond, body) => - this(this(x, cond), body) - case Try(block, handler, finalizer) => - this(this(this(x, block), handler), finalizer) - case SeqLiteral(elems, elemtpt) => - this(this(x, elems), elemtpt) - case Inlined(call, bindings, expansion) => - this(this(x, bindings), expansion)(inlineContext(call)) - case TypeTree() => - x - case SingletonTypeTree(ref) => - this(x, ref) - case AndTypeTree(left, right) => - this(this(x, left), right) - case OrTypeTree(left, right) => - this(this(x, left), right) - case RefinedTypeTree(tpt, refinements) => - this(this(x, tpt), refinements) - case AppliedTypeTree(tpt, args) => - this(this(x, tpt), args) - case LambdaTypeTree(tparams, body) => - implicit val ctx = localCtx - this(this(x, tparams), body) - case MatchTypeTree(bound, selector, cases) => - this(this(this(x, bound), selector), cases) - case ByNameTypeTree(result) => - this(x, result) - case TypeBoundsTree(lo, hi) => - this(this(x, lo), hi) - case Bind(name, body) => - this(x, body) - case Alternative(trees) => - this(x, trees) - case UnApply(fun, implicits, patterns) => - this(this(this(x, fun), implicits), patterns) - case tree @ ValDef(name, tpt, _) => - implicit val ctx = localCtx - this(this(x, tpt), tree.rhs) - case tree @ DefDef(name, tparams, vparamss, tpt, _) => - implicit val ctx = localCtx - this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs) - case TypeDef(name, rhs) => - implicit val ctx = localCtx - this(x, rhs) - case tree @ Template(constr, parents, self, _) => - this(this(this(this(x, constr), parents), self), tree.body) - case Import(expr, selectors) => - this(x, expr) - case PackageDef(pid, stats) => - this(this(x, pid), stats)(localCtx) - case Annotated(arg, annot) => - this(this(x, arg), annot) - case Thicket(ts) => - this(x, ts) - case _ => - foldMoreCases(x, tree) - } + def localCtx = + if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx + tree match { + case Ident(name) => + x + case Select(qualifier, name) => + this(x, qualifier) + case This(qual) => + x + case Super(qual, mix) => + this(x, qual) + case Apply(fun, args) => + this(this(x, fun), args) + case TypeApply(fun, args) => + this(this(x, fun), args) + case Literal(const) => + x + case New(tpt) => + this(x, tpt) + case Typed(expr, tpt) => + this(this(x, expr), tpt) + case NamedArg(name, arg) => + this(x, arg) + case Assign(lhs, rhs) => + this(this(x, lhs), rhs) + case Block(stats, expr) => + this(this(x, stats), expr) + case If(cond, thenp, elsep) => + this(this(this(x, cond), thenp), elsep) + case Closure(env, meth, tpt) => + this(this(this(x, env), meth), tpt) + case Match(selector, cases) => + this(this(x, selector), cases) + case CaseDef(pat, guard, body) => + this(this(this(x, pat), guard), body) + case Labeled(bind, expr) => + this(this(x, bind), expr) + case Return(expr, from) => + this(this(x, expr), from) + case WhileDo(cond, body) => + this(this(x, cond), body) + case Try(block, handler, finalizer) => + this(this(this(x, block), handler), finalizer) + case SeqLiteral(elems, elemtpt) => + this(this(x, elems), elemtpt) + case Inlined(call, bindings, expansion) => + this(this(x, bindings), expansion)(inlineContext(call)) + case TypeTree() => + x + case SingletonTypeTree(ref) => + this(x, ref) + case AndTypeTree(left, right) => + this(this(x, left), right) + case OrTypeTree(left, right) => + this(this(x, left), right) + case RefinedTypeTree(tpt, refinements) => + this(this(x, tpt), refinements) + case AppliedTypeTree(tpt, args) => + this(this(x, tpt), args) + case LambdaTypeTree(tparams, body) => + implicit val ctx = localCtx + this(this(x, tparams), body) + case MatchTypeTree(bound, selector, cases) => + this(this(this(x, bound), selector), cases) + case ByNameTypeTree(result) => + this(x, result) + case TypeBoundsTree(lo, hi) => + this(this(x, lo), hi) + case Bind(name, body) => + this(x, body) + case Alternative(trees) => + this(x, trees) + case UnApply(fun, implicits, patterns) => + this(this(this(x, fun), implicits), patterns) + case tree @ ValDef(name, tpt, _) => + implicit val ctx = localCtx + this(this(x, tpt), tree.rhs) + case tree @ DefDef(name, tparams, vparamss, tpt, _) => + implicit val ctx = localCtx + this(this((this(x, tparams) /: vparamss)(apply), tpt), tree.rhs) + case TypeDef(name, rhs) => + implicit val ctx = localCtx + this(x, rhs) + case tree @ Template(constr, parents, self, _) if tree.derived.isEmpty => + this(this(this(this(x, constr), parents), self), tree.body) + case Import(expr, selectors) => + this(x, expr) + case PackageDef(pid, stats) => + this(this(x, pid), stats)(localCtx) + case Annotated(arg, annot) => + this(this(x, arg), annot) + case Thicket(ts) => + this(x, ts) + case _ => + foldMoreCases(x, tree) + } } def foldMoreCases(x: X, tree: Tree)(implicit ctx: Context): X = { diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 4bec4ee635d8..4edaee7b7e40 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -293,7 +293,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val findLocalDummy = new FindLocalDummyAccumulator(cls) val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy.apply) .orElse(ctx.newLocalDummy(cls)) - val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body) + val impl = untpd.Template(constr, parents, Nil, selfType, newTypeParams ++ body) .withType(localDummy.termRef) ta.assignType(untpd.TypeDef(cls.name, impl), cls) } diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 26d95104a1ac..ddb6f6ab121b 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -39,7 +39,19 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def withName(name: Name)(implicit ctx: Context): ModuleDef = cpy.ModuleDef(this)(name.toTermName, impl) } - case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree)(implicit @constructorOnly src: SourceFile) extends Tree with TermTree + /** An untyped template with a derives clause. Derived parents are added to the end + * of the `parents` list. `derivedCount` keeps track of how many there are. + * This representation was chosen because it balances two concerns: + * - maximize overlap between DerivingTemplate and Template for code streamlining + * - keep invariant that elements of untyped trees align with source positions + */ + class DerivingTemplate(constr: DefDef, parentsOrDerived: List[Tree], self: ValDef, preBody: LazyTreeList, derivedCount: Int)(implicit @constructorOnly src: SourceFile) + extends Template(constr, parentsOrDerived, self, preBody) { + override val parents = parentsOrDerived.dropRight(derivedCount) + override val derived = parentsOrDerived.takeRight(derivedCount) + } + + case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree case class SymbolLit(str: String)(implicit @constructorOnly src: SourceFile) extends TermTree @@ -303,7 +315,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs) def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs) def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs) - def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template = new Template(constr, parents, self, body) + def Template(constr: DefDef, parents: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template = + if (derived.isEmpty) new Template(constr, parents, self, body) + else new DerivingTemplate(constr, parents ++ derived, self, body, derived.length) def Import(expr: Tree, selectors: List[Tree])(implicit src: SourceFile): Import = new Import(expr, selectors) def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats) def Annotated(arg: Tree, annot: Tree)(implicit src: SourceFile): Annotated = new Annotated(arg, annot) @@ -431,8 +445,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { case _ => finalize(tree, untpd.ModuleDef(name, impl)(tree.source)) } def ParsedTry(tree: Tree)(expr: Tree, handler: Tree, finalizer: Tree)(implicit ctx: Context): TermTree = tree match { - case tree: ParsedTry - if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree + case tree: ParsedTry if (expr eq tree.expr) && (handler eq tree.handler) && (finalizer eq tree.finalizer) => tree case _ => finalize(tree, untpd.ParsedTry(expr, handler, finalizer)(tree.source)) } def SymbolLit(tree: Tree)(str: String)(implicit ctx: Context): TermTree = tree match { @@ -513,6 +526,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def transformMoreCases(tree: Tree)(implicit ctx: Context): Tree = tree match { case ModuleDef(name, impl) => cpy.ModuleDef(tree)(name, transformSub(impl)) + case tree: DerivingTemplate => + cpy.Template(tree)(transformSub(tree.constr), transform(tree.parents), transform(tree.derived), transformSub(tree.self), transformStats(tree.body)) case ParsedTry(expr, handler, finalizer) => cpy.ParsedTry(tree)(transform(expr), transform(handler), transform(finalizer)) case SymbolLit(str) => @@ -560,6 +575,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { override def foldMoreCases(x: X, tree: Tree)(implicit ctx: Context): X = tree match { case ModuleDef(name, impl) => this(x, impl) + case tree: DerivingTemplate => + this(this(this(this(this(x, tree.constr), tree.parents), tree.derived), tree.self), tree.body) case ParsedTry(expr, handler, finalizer) => this(this(this(x, expr), handler), finalizer) case SymbolLit(str) => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f90ff942ff61..381ac0839e19 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -912,7 +912,7 @@ class TreeUnpickler(reader: TastyReader, tparams ++ vparams ++ stats }) setSpan(start, - untpd.Template(constr, mappedParents, self, lazyStats) + untpd.Template(constr, mappedParents, Nil, self, lazyStats) .withType(localDummy.termRef)) } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index fd02618c3111..ed0c57340cac 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -1057,7 +1057,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val parents = times(readNat(), () => readTreeRef()) val self = readValDefRef() val body = until(end, () => readTreeRef()) - untpd.Template(???, parents, self, body) // !!! TODO: pull out primary constructor + untpd.Template(???, parents, Nil, self, body) // !!! TODO: pull out primary constructor .withType(symbol.namedType) case BLOCKtree => diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index d1ad08e251ff..88fcedee0677 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -125,7 +125,7 @@ object JavaParsers { stats1 = constr1 :: stats1 constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, Flags.JavaDefined | Flags.PrivateLocal) } - Template(constr1.asInstanceOf[DefDef], parents, EmptyValDef, stats1) + Template(constr1.asInstanceOf[DefDef], parents, Nil, EmptyValDef, stats1) } def makeSyntheticParam(count: Int, tpt: Tree): ValDef = @@ -623,8 +623,8 @@ object JavaParsers { else { val template = cdef.rhs.asInstanceOf[Template] cpy.TypeDef(cdef)(cdef.name, - cpy.Template(template)(template.constr, template.parents, template.self, - importCompanionObject(cdef) :: template.body)).withMods(cdef.mods) + cpy.Template(template)(body = importCompanionObject(cdef) :: template.body)) + .withMods(cdef.mods) } List(makeCompanionObject(cdefNew, statics), cdefNew) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 3be24beee17a..04ddc52c2e47 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -649,8 +649,7 @@ object Parsers { /** QualId ::= id {`.' id} */ - val qualId: () => Tree = - () => dotSelectors(termIdent()) + def qualId(): Tree = dotSelectors(termIdent()) /** SimpleExpr ::= literal * | symbol @@ -1504,7 +1503,7 @@ object Parsers { case parent :: Nil if in.token != LBRACE => reposition(if (parent.isType) ensureApplied(wrapNew(parent)) else parent) case _ => - New(reposition(templateBodyOpt(emptyConstructor, parents, isEnum = false))) + New(reposition(templateBodyOpt(emptyConstructor, parents, Nil, isEnum = false))) } } @@ -2486,7 +2485,7 @@ object Parsers { tokenSeparated(WITH, constrApp) } else Nil - Template(constr, parents, EmptyValDef, Nil) + Template(constr, parents, Nil, EmptyValDef, Nil) } /* -------- TEMPLATES ------------------------------------------- */ @@ -2534,7 +2533,7 @@ object Parsers { val derived = if (isIdent(nme.derives)) { in.nextToken() - tokenSeparated(COMMA, qualId) + tokenSeparated(COMMA, () => convertToTypeId(qualId())) } else Nil (extended, derived) @@ -2543,11 +2542,11 @@ object Parsers { /** Template ::= InheritClauses [TemplateBody] */ def template(constr: DefDef, isEnum: Boolean = false): Template = { - val (parents, deriveds) = inheritClauses() + val (parents, derived) = inheritClauses() newLineOptWhenFollowedBy(LBRACE) if (isEnum && in.token != LBRACE) syntaxErrorOrIncomplete(ExpectedTokenButFound(LBRACE, in.token)) - templateBodyOpt(constr, parents, isEnum) + templateBodyOpt(constr, parents, derived, isEnum) } /** TemplateOpt = [Template] @@ -2557,15 +2556,15 @@ object Parsers { if (in.token == EXTENDS || isIdent(nme.derives) || in.token == LBRACE) template(constr, isEnum) else - Template(constr, Nil, EmptyValDef, Nil) + Template(constr, Nil, Nil, EmptyValDef, Nil) } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ - def templateBodyOpt(constr: DefDef, parents: List[Tree], isEnum: Boolean): Template = { + def templateBodyOpt(constr: DefDef, parents: List[Tree], derived: List[Tree], isEnum: Boolean): Template = { val (self, stats) = if (in.token == LBRACE) withinEnum(isEnum)(templateBody()) else (EmptyValDef, Nil) - Template(constr, parents, self, stats) + Template(constr, parents, derived, self, stats) } def templateBody(): (ValDef, List[Tree]) = { diff --git a/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala b/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala index 9630bdc98c87..7b51af00b378 100644 --- a/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/DecompilerPrinter.scala @@ -69,7 +69,7 @@ class DecompilerPrinter(_ctx: Context) extends RefinedPrinter(_ctx) { val bodyText = " {" ~~ toTextGlobal(impl.body, "\n") ~ "}" parentsText.provided(parents.nonEmpty) ~ bodyText } - else super.toTextTemplate(impl.copy(parents = parents, preBody = body), ofNew) + else super.toTextTemplate(impl.copy(parentsOrDerived = parents, preBody = body), ofNew) } override protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text = { diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 5344e738e79c..ed90e482a9c2 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -700,7 +700,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } protected def toTextTemplate(impl: Template, ofNew: Boolean = false): Text = { - val Template(constr @ DefDef(_, tparams, vparamss, _, _), parents, self, _) = impl + val Template(constr @ DefDef(_, tparams, vparamss, _, _), _, self, _) = impl val tparamsTxt = withEnclosingDef(constr) { tparamsText(tparams) } val primaryConstrs = if (constr.rhs.isEmpty) Nil else constr :: Nil val prefix: Text = @@ -711,7 +711,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (constr.mods.hasAnnotations && !constr.mods.hasFlags) modsText = modsText ~~ " this" withEnclosingDef(constr) { addVparamssText(tparamsTxt ~~ modsText, vparamss) } } - val parentsText = Text(parents map constrText, keywordStr(" with ")) + val parentsText = Text(impl.parents.map(constrText), if (ofNew) keywordStr(" with ") else ", ") + val derivedText = Text(impl.derived.map(toText(_)), ", ") val selfText = { val selfName = if (self.name == nme.WILDCARD) keywordStr("this") else self.name.toString (selfName ~ optText(self.tpt)(": " ~ _) ~ " =>").close @@ -729,7 +730,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { val bodyText = " {" ~~ selfText ~~ toTextGlobal(primaryConstrs ::: body, "\n") ~ "}" - prefix ~ keywordText(" extends").provided(!ofNew && parents.nonEmpty) ~~ parentsText ~ bodyText + prefix ~ + keywordText(" extends").provided(!ofNew && impl.parents.nonEmpty) ~~ parentsText ~ + keywordText(" derives").provided(impl.derived.nonEmpty) ~~ derivedText ~ + bodyText } protected def templateText(tree: TypeDef, impl: Template): Text = { diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index 93045ba44686..f8448696f1b0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Constructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/Constructors.scala @@ -281,8 +281,6 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = } else cpy.DefDef(constr)(rhs = Block(finalConstrStats, unitLiteral)) - cpy.Template(tree)( - constr = expandedConstr, - body = clsStats.toList) + cpy.Template(tree)(constr = expandedConstr, body = clsStats.toList) } } diff --git a/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala b/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala index 042e400bc3d0..f0053b3abfe9 100644 --- a/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/MacroTransform.scala @@ -56,6 +56,7 @@ abstract class MacroTransform extends Phase { cpy.Template(tree)( transformSub(constr), transform(parents)(ctx.superCallContext), + Nil, transformSelf(self), transformStats(impl.body, tree.symbol)) case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala index 58e88b54acef..c42e6e1b7132 100644 --- a/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala +++ b/compiler/src/dotty/tools/dotc/transform/MegaPhase.scala @@ -337,7 +337,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase { val parents = transformTrees(tree.parents, start)(ctx.superCallContext) val self = transformSpecificTree(tree.self, start) val body = transformStats(tree.body, tree.symbol, start) - goTemplate(cpy.Template(tree)(constr, parents, self, body), start) + goTemplate(cpy.Template(tree)(constr, parents, Nil, self, body), start) case tree: Match => implicit val ctx = prepMatch(tree, start)(outerCtx) val selector = transformTree(tree.selector, start) diff --git a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala index 8b06551fb1d4..059ab19165cf 100644 --- a/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala +++ b/compiler/src/dotty/tools/dotc/transform/MoveStatics.scala @@ -54,7 +54,7 @@ class MoveStatics extends MiniPhase with SymTransformer { } else newBody val oldTemplate = orig.rhs.asInstanceOf[Template] - cpy.TypeDef(orig)(rhs = cpy.Template(orig.rhs)(oldTemplate.constr, oldTemplate.parents, oldTemplate.self, newBodyWithStaticConstr)) + cpy.TypeDef(orig)(rhs = cpy.Template(oldTemplate)(body = newBodyWithStaticConstr)) } def move(module: TypeDef, companion: TypeDef): List[Tree] = { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index c107b091d4b5..e6936536454c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -531,14 +531,20 @@ class Namer { typer: Typer => to.putAttachment(References, fromRefs ++ toRefs) } - /** Merge the module class `modCls` in the expanded tree of `mdef` with the given stats */ - def mergeModuleClass(mdef: Tree, modCls: TypeDef, stats: List[Tree]): TypeDef = { + /** Merge the module class `modCls` in the expanded tree of `mdef` with the + * body and derived clause of the syntehtic module class `fromCls`. + */ + def mergeModuleClass(mdef: Tree, modCls: TypeDef, fromCls: TypeDef): TypeDef = { var res: TypeDef = null val Thicket(trees) = expanded(mdef) val merged = trees.map { tree => if (tree == modCls) { - val impl = modCls.rhs.asInstanceOf[Template] - res = cpy.TypeDef(modCls)(rhs = cpy.Template(impl)(body = stats ++ impl.body)) + val fromTempl = fromCls.rhs.asInstanceOf[Template] + val modTempl = modCls.rhs.asInstanceOf[Template] + res = cpy.TypeDef(modCls)( + rhs = cpy.Template(modTempl)( + derived = fromTempl.derived ++ modTempl.derived, + body = fromTempl.body ++ modTempl.body)) res } else tree @@ -559,7 +565,7 @@ class Namer { typer: Typer => def mergeIfSynthetic(fromStat: Tree, fromCls: TypeDef, toStat: Tree, toCls: TypeDef): Unit = if (fromCls.mods.is(Synthetic) && !toCls.mods.is(Synthetic)) { removeInExpanded(fromStat, fromCls) - val mcls = mergeModuleClass(toStat, toCls, fromCls.rhs.asInstanceOf[Template].body) + val mcls = mergeModuleClass(toStat, toCls, fromCls) mcls.setMods(toCls.mods | (fromCls.mods.flags & RetainedSyntheticCompanionFlags)) moduleClsDef(fromCls.name) = (toStat, mcls) } @@ -838,7 +844,7 @@ class Namer { typer: Typer => protected implicit val ctx: Context = localContext(cls).setMode(ictx.mode &~ Mode.InSuperCall) - val TypeDef(name, impl @ Template(constr, parents, self, _)) = original + val TypeDef(name, impl @ Template(constr, _, self, _)) = original private val (params, rest): (List[Tree], List[Tree]) = impl.body.span { case td: TypeDef => td.mods is Param @@ -850,6 +856,7 @@ class Namer { typer: Typer => /** The type signature of a ClassDef with given symbol */ override def completeInCreationContext(denot: SymDenotation): Unit = { + val parents = impl.parents /* The type of a parent constructor. Types constructor arguments * only if parent type contains uninstantiated type parameters. @@ -909,6 +916,23 @@ class Namer { typer: Typer => } } + /* Check derived type tree `derived` for the following well-formedness conditions: + * (1) It must be a class type with a stable prefix (@see checkClassTypeWithStablePrefix) + * (2) It must have exactly one type parameter + * If it passes the checks, enter a typeclass instance for it in the class scope. + */ + def addDerivedInstance(derived: untpd.Tree): Unit = { + val uncheckedType = typedAheadType(derived, AnyTypeConstructorProto).tpe.dealiasKeepAnnots + val derivedType = checkClassType(uncheckedType, derived.pos, traitReq = false, stablePrefixReq = true) + val nparams = derivedType.typeSymbol.typeParams.length + if (nparams == 1) + println(i"todo: add derived instance $derived") + else + ctx.error( + i"derived class $derivedType should have one type paramater but has $nparams", + derived.pos) + } + addAnnotations(denot.symbol) val selfInfo: TypeOrSymbol = @@ -939,6 +963,8 @@ class Namer { typer: Typer => ensureFirstIsClass(parents.map(checkedParentType(_)), cls.span)) typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %") + impl.derived.foreach(addDerivedInstance) + val finalSelfInfo: TypeOrSymbol = if (cls.isOpaqueCompanion) { // The self type of an opaque companion is refined with the type-alias of the original opaque type diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0b726256c0b3..15d8a595af9a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1556,7 +1556,8 @@ class Typer extends Namer def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context): Tree = track("typedClassDef") { if (!cls.info.isInstanceOf[ClassInfo]) return EmptyTree.assertingErrorsReported - val TypeDef(name, impl @ Template(constr, parents, self, _)) = cdef + val TypeDef(name, impl @ Template(constr, _, self, _)) = cdef + val parents = impl.parents val superCtx = ctx.superCallContext /** If `ref` is an implicitly parameterized trait, pass an implicit argument list. @@ -1625,6 +1626,7 @@ class Typer extends Namer val constr1 = typed(constr).asInstanceOf[DefDef] val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.nameSpan) val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx) + var self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible if (cls.isOpaqueCompanion && !ctx.isAfterTyper) { // this is necessary to ensure selftype is correctly pickled @@ -1639,7 +1641,7 @@ class Typer extends Namer typedStats(impl.body, dummy)(ctx.inClassContext(self1.symbol))) checkNoDoubleDeclaration(cls) - val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) + val impl1 = cpy.Template(impl)(constr1, parents1, Nil, self1, body1) .withType(dummy.termRef) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls, cdef.sourcePos.withSpan(cdef.nameSpan)) diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 6093f91d277e..61d7c244fb70 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -130,7 +130,7 @@ class ReplCompiler extends Compiler { implicit val ctx: Context = defs.state.context - val tmpl = Template(emptyConstructor, Nil, EmptyValDef, defs.stats) + val tmpl = Template(emptyConstructor, Nil, Nil, EmptyValDef, defs.stats) val module = ModuleDef(objectTermName, tmpl) .withSpan(Span(0, defs.stats.last.span.end)) @@ -229,8 +229,9 @@ class ReplCompiler extends Compiler { def wrapped(expr: String, sourceFile: SourceFile, state: State)(implicit ctx: Context): Result[untpd.PackageDef] = { def wrap(trees: List[untpd.Tree]): untpd.PackageDef = { import untpd._ + val valdef = ValDef("expr".toTermName, TypeTree(), Block(trees, unitLiteral).withSpan(Span(0, expr.length))) - val tmpl = Template(emptyConstructor, Nil, EmptyValDef, List(valdef)) + val tmpl = Template(emptyConstructor, Nil, Nil, EmptyValDef, List(valdef)) val wrapper = TypeDef("$wrapper".toTypeName, tmpl) .withMods(Modifiers(Final)) .withSpan(Span(0, expr.length)) diff --git a/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala b/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala index 4624b39d3e5e..e8c9412a49c4 100644 --- a/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala +++ b/compiler/test/dotty/tools/dotc/parsing/DeSugarTest.scala @@ -64,7 +64,7 @@ class DeSugarTest extends ParserTest { case tree1 @ TypeDef(name, rhs) => cpy.TypeDef(tree1)(name, transform(rhs, Type)) case impl @ Template(constr, parents, self, _) => - cpy.Template(tree1)(transformSub(constr), transform(parents), transformSub(self), transform(impl.body, Expr)) + cpy.Template(tree1)(transformSub(constr), transform(parents), Nil, transformSub(self), transform(impl.body, Expr)) case Thicket(trees) => Thicket(flatten(trees mapConserve super.transform)) case tree1 =>