From 8168f118c9f71d63404880de89f20471043949fe Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 23 Feb 2013 13:40:14 +0100 Subject: [nomaster] SI-7167 implicit macros decide what is divergence Imagine a macro writer which wants to synthesize a complex implicit Complex[T] by making recursive calls to Complex[U] for its parts. E.g. if we have `class Foo(val bar: Bar)` and `class Bar(val x: Int)`, then it's quite reasonable for the macro writer to synthesize Complex[Foo] by calling `inferImplicitValue(typeOf[Complex[Bar])`. However if we didn't insert `info.sym.isMacro` check in `typedImplicit`, then under some circumstances (e.g. as described in http://groups.google.com/group/scala-internals/browse_thread/thread/545462b377b0ac0a) `dominates` might decide that `Bar` dominates `Foo` and therefore a recursive implicit search should be prohibited. Now when we yield control of divergent expansions to the macro writer, what happens next? In the worst case, if the macro writer is careless, we'll get a StackOverflowException from repeated macro calls. Otherwise, the macro writer could check `c.openMacros` and `c.openImplicits` and do `c.abort` when expansions are deemed to be divergent. Upon receiving `c.abort` the typechecker will decide that the corresponding implicit search has failed which will fail the entire stack of implicit searches, producing a nice error message provided by the macro writer. NOTE: the original commit from macro paradise also introduced a new class, which encapsulates information about implicits in flight. Unfortunately we cannot do that in 2.10.x, because of binary compatibility concerns, therefore I'm marking this commit as [nomaster] and will be resubmitting its full version in a separate pull request exclusively targetting master. --- src/reflect/scala/reflect/macros/Enclosures.scala | 6 +++++- src/reflect/scala/reflect/macros/Typers.scala | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala index c48656b366..a4ad71c348 100644 --- a/src/reflect/scala/reflect/macros/Enclosures.scala +++ b/src/reflect/scala/reflect/macros/Enclosures.scala @@ -29,8 +29,12 @@ trait Enclosures { */ val enclosingMacros: List[Context] - /** Types along with corresponding trees for which implicit arguments are currently searched. + /** Information about one of the currently considered implicit candidates. + * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters, + * hence implicit searches can recursively trigger other implicit searches. + * * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion. + * If we're in an implicit macro being expanded, it's included in this list. * * Unlike `openImplicits`, this is a val, which means that it gets initialized when the context is created * and always stays the same regardless of whatever happens during macro expansion. diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala index 427e7854b2..d36636a6d2 100644 --- a/src/reflect/scala/reflect/macros/Typers.scala +++ b/src/reflect/scala/reflect/macros/Typers.scala @@ -24,8 +24,12 @@ trait Typers { */ def openMacros: List[Context] - /** Types along with corresponding trees for which implicit arguments are currently searched. + /** Information about one of the currently considered implicit candidates. + * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters, + * hence implicit searches can recursively trigger other implicit searches. + * * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion. + * If we're in an implicit macro being expanded, it's included in this list. * * Unlike `enclosingImplicits`, this is a def, which means that it gets recalculated on every invocation, * so it might change depending on what is going on during macro expansion. -- cgit v1.2.3