From 84b6b5d45c6875a5a6299af985505fc41dc2e5af Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 19 Oct 2016 12:35:55 +0300 Subject: [PATCH] convert type members Inspired by https://github.com/scalameta/paradise/pull/96. --- .../paradise/converters/LogicalTrees.scala | 8 +++++++- .../scalameta/paradise/converters/ToMtree.scala | 7 +++++++ .../converter/src/main/scala/ConverterSuite.scala | 15 ++++++++++++++- tests/converter/src/test/scala/Syntactic.scala | 12 ++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/scala/org/scalameta/paradise/converters/LogicalTrees.scala b/plugin/src/main/scala/org/scalameta/paradise/converters/LogicalTrees.scala index f60abb80..6fe4dbc8 100644 --- a/plugin/src/main/scala/org/scalameta/paradise/converters/LogicalTrees.scala +++ b/plugin/src/main/scala/org/scalameta/paradise/converters/LogicalTrees.scala @@ -713,7 +713,13 @@ class LogicalTrees[G <: Global](val global: G, root: G#Tree) extends ReflectTool object TypeDef { def unapply( tree: g.TypeDef): Option[(List[l.Modifier], l.TypeName, List[l.TypeParamDef], g.Tree)] = { - ??? + tree match { + case g.TypeDef(mods, name, tparams, rhs) if !mods.hasFlag(DEFERRED) => + val ltparams = mkTparams(tparams, Nil) + Some((l.Modifiers(tree), l.TypeName(tree), ltparams, rhs)) + case _ => + None + } } } diff --git a/plugin/src/main/scala/org/scalameta/paradise/converters/ToMtree.scala b/plugin/src/main/scala/org/scalameta/paradise/converters/ToMtree.scala index 13081bd4..7d3f5bdb 100644 --- a/plugin/src/main/scala/org/scalameta/paradise/converters/ToMtree.scala +++ b/plugin/src/main/scala/org/scalameta/paradise/converters/ToMtree.scala @@ -310,6 +310,13 @@ trait ToMtree { self: Converter => val mrhs = lrhs.toMtree[m.Term] m.Defn.Def(mmods, mname, mtparams, mparamss, mtpt, mrhs) + case l.TypeDef(lmods, lname, ltparams, lbody) => + val mmods = lmods.toMtrees[m.Mod] + val mname = lname.toMtree[m.Type.Name] + val mtparams = ltparams.toMtrees[m.Type.Param] + val mbody = lbody.toMtree[m.Type] + m.Defn.Type(mmods, mname, mtparams, mbody) + case l.ClassDef(lmods, lname, ltparams, lctor, limpl) => val mmods = lmods.toMtrees[m.Mod] val mname = lname.toMtree[m.Type.Name] diff --git a/tests/converter/src/main/scala/ConverterSuite.scala b/tests/converter/src/main/scala/ConverterSuite.scala index c6b1a31c..a0819984 100644 --- a/tests/converter/src/main/scala/ConverterSuite.scala +++ b/tests/converter/src/main/scala/ConverterSuite.scala @@ -100,7 +100,20 @@ trait ConverterSuite extends FunSuite { import g._ val reporter = new StoreReporter() g.reporter = reporter - val tree = gen.mkTreeOrBlock(newUnitParser(code, "").parseStatsOrPackages()) + val tree = { + // NOTE: `parseStatsOrPackages` fails to parse abstract type defs without bounds, + // so we need to apply a workaround to ensure that we correctly process those. + def somewhatBrokenParse(code: String) = + gen.mkTreeOrBlock(newUnitParser(code, "").parseStatsOrPackages()) + val rxAbstractTypeNobounds = """^type (\w+)(\[[^=]*?\])?$""".r + code match { + case rxAbstractTypeNobounds(_ *) => + val tdef @ TypeDef(mods, name, tparams, _) = somewhatBrokenParse(code + " <: Dummy") + treeCopy.TypeDef(tdef, mods, name, tparams, TypeBoundsTree(EmptyTree, EmptyTree)) + case _ => + somewhatBrokenParse(code) + } + } val errors = reporter.infos.filter(_.severity == g.reporter.ERROR) errors.foreach(error => fail(s"scalac parse error: ${error.msg} at ${error.pos}")) tree diff --git a/tests/converter/src/test/scala/Syntactic.scala b/tests/converter/src/test/scala/Syntactic.scala index f41caa2e..11734349 100644 --- a/tests/converter/src/test/scala/Syntactic.scala +++ b/tests/converter/src/test/scala/Syntactic.scala @@ -104,6 +104,18 @@ class Syntactic extends ConverterSuite { syntactic("a match { case x @ _ => }") syntactic("a match { case x @ (_: T) => }") + // definitions + syntactic("type Age = Int") + syntactic("type Age") + syntactic("type Age >: Int <: Any") + syntactic("type Age <: Int + Boolean") + syntactic("type Container[T]") + syntactic("type Container[T] = List[T]") + syntactic("type Container[T] <: List[T] { def isEmpty: Boolean; type M }") + syntactic("type Container[T] <: List[T] with Set[T] { def isEmpty: Boolean; type M }") + syntactic("type Container[T] <: List[T] with Set[T] { def isEmpty: Boolean; type M = Int }") + syntactic("type Container[T] <: List[T] with Set[T] { def isEmpty: Boolean; type M <: Int }") + // types syntactic("val a: A with B = ???") syntactic("val a: A { def x: Int } = ???")