scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Anonymous class creation with empty body list in quasiquotes #10691

Closed cornerman closed 6 years ago

cornerman commented 6 years ago

In a macro, I am instantiating a trait and generate method implementations for it.

val bodyList: List[Tree] = ???

q"trait Tret; new Tret { ...$bodyList }"

This works as expected as long as bodyList is non-empty. But as soon as it is empty, the generate code looks like this: q"trait Tret; new Tret()". This is missing the { } at the end, which will not compile, as a trait can only be instantiated as an anonymous class.

It does not behave the same as an explicitly empty body:

scala> val bodyList: List[Tree] = Nil
bodyList: List[reflect.runtime.universe.Tree] = List()

scala> q"trait Tret; new Tret { ..$bodyList } "
res3: reflect.runtime.universe.Tree =
{
  abstract trait Tret extends scala.AnyRef;
  new Tret()
}

scala> q"trait Tret; new Tret { } "
res4: reflect.runtime.universe.Tree =
{
  abstract trait Tret extends scala.AnyRef;
  {
    final class $anon extends Tret {
      def <init>() = {
        super.<init>();
        ()
      };
      <empty>
    };
    new $anon()
  }
}
joroKr21 commented 6 years ago

On the other hand, you probably don't want to create a new anonymous class when Tret is a (non-abstract) class.

cornerman commented 6 years ago

On the other hand, you probably don't want to create a new anonymous class when Tret is a (non-abstract) class.

You are right, but for an abstract class or a trait, it does not make sense.

joroKr21 commented 6 years ago

inevitably someone will come up with the following example:

def foo = new util.Random().nextBoolean()
class C; trait T
q"new ${if (foo) typeOf[C] else typeOf[T]} { ..${List.empty[Tree]} }"

Besides, quasiquotes are untyped - they don't know the difference between a class and a trait if all they are given is a name for example.

I guess we can't have the best usability in both scenarios - it's a trade-off.

Arguably always creating the anonymous class is more precise because there are explicit brackets in the quasiquote. But there are similar syntactic constructs that wouldn't make sense anymore, e.g. type arguments: q"method[..${List.empty[Type]}]".

I doubt a change like this is likely to make it in since macros will be completely revamped anyway.

cornerman commented 6 years ago

Good point! It just triggered an unexpected bug in my macro when generating an implementation for a type without abstract members, so I wanted to mention it here. A fix is probably not worth it given the coming deprecation of the current macro system, as you already said.

som-snytt commented 6 years ago

A workaround is to use List(EmptyTree) instead of an empty list for statements.

SethTisue commented 6 years ago

closing all quasiquotes tickets; see #10755