You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: overviews/macros/inference.md
+23-11Lines changed: 23 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -15,11 +15,6 @@ languages: [ja]
15
15
16
16
Inference-driving macros are pre-release features included in so-called macro paradise, an experimental branch in the official Scala repository. Follow the instructions at the ["Macro Paradise"](/overviews/macros/paradise.html) page to download and use our nightly builds.
17
17
18
-
WARNING! This is the most experimental of all the experimental features in paradise. Not only the details of the API are unclear,
19
-
but I'm not sure whether the current approach is the right one, unlike, for example, in type macros, where things look very solid.
20
-
Your feedback is even more welcome than ever. If you scroll down, you can leave comments directly on this page. You could also participate
21
-
in the [discussion at scala-internals](http://groups.google.com/group/scala-internals/browse_thread/thread/ad309e68d645b775).
22
-
23
18
## A motivating example
24
19
25
20
The use case, which gave birth to inference-driving macros, is provided by Miles Sabin and his [shapeless](https://github.com/milessabin/shapeless) library. Miles has defined the `Iso` trait, which represents isomorphisms between types.
@@ -46,15 +41,29 @@ classes and HLists, but for simplicity let's use tuples). The compiler already g
46
41
and we just have to make use of them. Unfortunately in Scala 2.10.0 it's impossible to simplify this even further - for every case class
47
42
you have manually define an implicit `Iso` instance.
48
43
49
-
Macros have proven to be quite the boilerplate scrapers, but unfortunately they can't help here in their 2.10.0 form. The problem
50
-
is not just in [SI-5923](https://issues.scala-lang.org/browse/SI-5923), which has already been fixed in master for a few weeks
51
-
(note to self: backport this fix to 2.10.1).
52
-
53
44
The real showstopper is the fact that when typechecking applications of methods like `foo`, scalac has to infer the type argument `L`,
54
45
which it has no clue about (and that's no wonder, since this is domain-specific knowledge). As a result, even if you define an implicit
55
46
macro, which synthesizes `Iso[C, L]`, scalac will helpfully infer `L` as `Nothing` before expanding the macro and then everything crumbles.
56
47
57
-
## Internals of type inference
48
+
## The proposed solution
49
+
50
+
As demonstrated by [https://github.com/scala/scala/pull/2499](https://github.com/scala/scala/pull/2499), the solution to the outlined
51
+
problem is extremely simple and elegant. <spanclass="label success">NEW</span>
52
+
53
+
In 2.10 we don't allow macro applications to expand until all their type arguments are inferred. However we don't have to do that.
54
+
The typechecker can infer as much as it possibly can (e.g. in the running example `C` will be inferred to `Foo` and
55
+
`L` will remain uninferred) and then stop. After that we expand the macro and then proceed with type inference using the type of the
56
+
expansion to help the typechecker with previously undetermined type arguments.
57
+
58
+
An illustration of this technique in action can be found in our [files/run/t5923c](https://github.com/scalamacros/kepler/tree/7b890f71ecd0d28c1a1b81b7abfe8e0c11bfeb71/test/files/run/t5923c) tests.
59
+
Note how simple everything is. The `materializeIso` implicit macro just takes its first type argument and uses it to produce an expansion.
60
+
We don't need to make sense of the second type argument (which isn't inferred yet), we don't need to interact with type inference -
61
+
everything happens automatically.
62
+
63
+
Please note that there is [a funny caveat](https://github.com/scalamacros/kepler/blob/7b890f71ecd0d28c1a1b81b7abfe8e0c11bfeb71/test/files/run/t5923a/Macros_1.scala)
64
+
with Nothings that we plan to address later.
65
+
66
+
## Internals of type inference (deprecated)
58
67
59
68
From what I learned about this over a few days, type inference in Scala is performed by the following two methods
60
69
in `scala/tools/nsc/typechecker/Infer.scala`: [`inferExprInstance`](https://github.com/scalamacros/kepler/blob/d7b59f452f5fa35df48a5e0385f579c98ebf3555/src/compiler/scala/tools/nsc/typechecker/Infer.scala#L1123) and
@@ -145,7 +154,10 @@ So far I have nothing to say here other than showing `-Yinfer-debug` logs of var
145
154
[solve types] solving for T4 in ?T4
146
155
[infer method] solving for T4 in (implicit xs: C.this.Qwe[T4])Nothing based on (C.this.Qwe[Nothing])Nothing (solved: T4=Nothing)
147
156
148
-
## Proposed solution
157
+
## Previously proposed solution (deprecated)
158
+
159
+
It turns out that it's unnecessary to introduce a low-level hack in the type inference mechanism.
160
+
As outlined above, there is a much more elegant and powerful solution <spanclass="label success">NEW</span>.
149
161
150
162
Using the infrastructure provided by [macro bundles](/overviews/macros/bundles.html) (in principle, we could achieve exactly the same
151
163
thing using the traditional way of defining macro implementations, but that's not important here), we introduce the `onInfer` callback,
0 commit comments