Skip to content

Commit 34b836b

Browse files
committed
Add copy of reference as TODO
reference taken from 7919cb3
1 parent 87f1e82 commit 34b836b

File tree

121 files changed

+15330
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+15330
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
layout: index
3+
title: "Other Changed Features"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features.html
5+
---
6+
7+
The following pages document the features that have changed in Scala 3, compared to Scala 2.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
layout: doc-page
3+
title: "Changes in Compiler Plugins"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/compiler-plugins.html
5+
---
6+
7+
Compiler plugins are supported by Dotty (and Scala 3) since 0.9. There are two notable changes
8+
compared to `scalac`:
9+
10+
- No support for analyzer plugins
11+
- Added support for research plugins
12+
13+
[Analyzer plugins][1] in `scalac` run during type checking and may influence
14+
normal type checking. This is a very powerful feature but for production usages,
15+
a predictable and consistent type checker is more important.
16+
17+
For experimentation and research, Scala 3 introduces _research plugin_. Research plugins
18+
are more powerful than `scalac` analyzer plugins as they let plugin authors customize
19+
the whole compiler pipeline. One can easily replace the standard typer by a custom one or
20+
create a parser for a domain-specific language. However, research plugins are only
21+
enabled for nightly or snaphot releases of Scala 3.
22+
23+
Common plugins that add new phases to the compiler pipeline are called
24+
_standard plugins_ in Scala 3. In terms of features, they are similar to
25+
`scalac` plugins, despite minor changes in the API.
26+
27+
## Using Compiler Plugins
28+
29+
Both standard and research plugins can be used with `scalac` by adding the `-Xplugin:` option:
30+
31+
```shell
32+
scalac -Xplugin:pluginA.jar -Xplugin:pluginB.jar Test.scala
33+
```
34+
35+
The compiler will examine the jar provided, and look for a property file named
36+
`plugin.properties` in the root directory of the jar. The property file specifies
37+
the fully qualified plugin class name. The format of a property file is as follows:
38+
39+
```properties
40+
pluginClass=dividezero.DivideZero
41+
```
42+
43+
This is different from `scalac` plugins that required a `scalac-plugin.xml` file.
44+
45+
Starting from 1.1.5, `sbt` also supports Scala 3 compiler plugins. Please refer to the
46+
[`sbt` documentation][2] for more information.
47+
48+
## Writing a Standard Compiler Plugin
49+
50+
Here is the source code for a simple compiler plugin that reports integer divisions by
51+
zero as errors.
52+
53+
```scala
54+
package dividezero
55+
56+
import dotty.tools.dotc.ast.Trees.*
57+
import dotty.tools.dotc.ast.tpd
58+
import dotty.tools.dotc.core.Constants.Constant
59+
import dotty.tools.dotc.core.Contexts.Context
60+
import dotty.tools.dotc.core.Decorators.*
61+
import dotty.tools.dotc.core.StdNames.*
62+
import dotty.tools.dotc.core.Symbols.*
63+
import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin}
64+
import dotty.tools.dotc.transform.{Pickler, Staging}
65+
66+
class DivideZero extends StandardPlugin:
67+
val name: String = "divideZero"
68+
override val description: String = "divide zero check"
69+
70+
def init(options: List[String]): List[PluginPhase] =
71+
(new DivideZeroPhase) :: Nil
72+
73+
class DivideZeroPhase extends PluginPhase:
74+
import tpd.*
75+
76+
val phaseName = "divideZero"
77+
78+
override val runsAfter = Set(Pickler.name)
79+
override val runsBefore = Set(Staging.name)
80+
81+
override def transformApply(tree: Apply)(implicit ctx: Context): Tree =
82+
tree match
83+
case Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0))))
84+
if rcvr.tpe <:< defn.IntType =>
85+
report.error("dividing by zero", tree.pos)
86+
case _ =>
87+
()
88+
tree
89+
end DivideZeroPhase
90+
```
91+
92+
The plugin main class (`DivideZero`) must extend the trait `StandardPlugin`
93+
and implement the method `init` that takes the plugin's options as argument
94+
and returns a list of `PluginPhase`s to be inserted into the compilation pipeline.
95+
96+
Our plugin adds one compiler phase to the pipeline. A compiler phase must extend
97+
the `PluginPhase` trait. In order to specify when the phase is executed, we also
98+
need to specify a `runsBefore` and `runsAfter` constraints that are list of phase
99+
names.
100+
101+
We can now transform trees by overriding methods like `transformXXX`.
102+
103+
## Writing a Research Compiler Plugin
104+
105+
Here is a template for research plugins.
106+
107+
```scala
108+
import dotty.tools.dotc.core.Contexts.Context
109+
import dotty.tools.dotc.core.Phases.Phase
110+
import dotty.tools.dotc.plugins.ResearchPlugin
111+
112+
class DummyResearchPlugin extends ResearchPlugin:
113+
val name: String = "dummy"
114+
override val description: String = "dummy research plugin"
115+
116+
def init(options: List[String], phases: List[List[Phase]])(implicit ctx: Context): List[List[Phase]] =
117+
phases
118+
end DummyResearchPlugin
119+
```
120+
121+
A research plugin must extend the trait `ResearchPlugin` and implement the
122+
method `init` that takes the plugin's options as argument as well as the compiler
123+
pipeline in the form of a list of compiler phases. The method can replace, remove
124+
or add any phases to the pipeline and return the updated pipeline.
125+
126+
127+
[1]: https://github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala
128+
[2]: https://www.scala-sbt.org/1.x/docs/Compiler-Plugins.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
layout: doc-page
3+
title: "Automatic Eta Expansion - More Details"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/eta-expansion-spec.html
5+
---
6+
7+
## Motivation
8+
9+
Scala maintains a convenient distinction between _methods_ and _functions_.
10+
Methods are part of the definition of a class that can be invoked in objects while functions are complete objects themselves, making them first-class entities. For example, they can be assigned to variables.
11+
These two mechanisms are bridged in Scala by a mechanism called
12+
[_eta-expansion_](https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#eta-expansion-section)
13+
(also called eta-abstraction), which converts a reference to a method into a function. Intuitively, a method `m` can be passed around by turning it into an object: the function `x => m(x)`.
14+
15+
In this snippet which assigns a method to a `val`, the compiler will perform _automatic eta-expansion_, as shown in the comment:
16+
17+
```scala
18+
def m(x: Int, y: String) = ???
19+
val f = m // becomes: val f = (x: Int, y: String) => m(x, y)
20+
```
21+
22+
In Scala 2, a method reference `m` is converted to a function value only if the expected type is a function type, which means the conversion in the example above would not have been triggered, because `val f` does not have a type ascription. To still get eta-expansion, a shortcut `m _` would force the conversion.
23+
24+
For methods with one or more parameters like in the example above, this restriction has now been dropped. The syntax `m _` is no longer needed and will be deprecated in the future.
25+
26+
## Automatic eta-expansion and partial application
27+
In the following example `m` can be partially applied to the first two parameters.
28+
Assigning `m` to `f1` will automatically eta-expand.
29+
30+
```scala
31+
def m(x: Boolean, y: String)(z: Int): List[Int]
32+
val f1 = m
33+
val f2 = m(true, "abc")
34+
```
35+
36+
This creates two function values:
37+
38+
```scala
39+
f1: (Boolean, String) => Int => List[Int]
40+
f2: Int => List[Int]
41+
```
42+
43+
## Automatic eta-expansion and implicit parameter lists
44+
45+
Methods with implicit parameter lists will always get applied to implicit arguments.
46+
47+
```scala
48+
def foo(x: Int)(implicit p: Double): Float = ???
49+
implicit val bla: Double = 1.0
50+
51+
val bar = foo // val bar: Int => Float = ...
52+
```
53+
54+
## Automatic Eta-Expansion and query types
55+
56+
A method with context parameters can be expanded to a value of a context type by writing the expected context type explicitly.
57+
58+
```scala
59+
def foo(x: Int)(using p: Double): Float = ???
60+
val bar: Double ?=> Float = foo(3)
61+
```
62+
63+
## Rules
64+
65+
- If `m` has an argument list with one or more parameters, we always eta-expand
66+
- If `m` is has an empty argument list (i.e. has type `()R`):
67+
1. If the expected type is of the form `() => T`, we eta expand.
68+
2. If m is defined by Java, or overrides a Java defined method, we insert `()`.
69+
3. Otherwise we issue an error of the form:
70+
71+
Thus, an unapplied method with an empty argument list is only converted to a function when a function type is expected. It is considered best practice to either explicitly apply the method to `()`, or convert it to a function with `() => m()`.
72+
73+
The method value syntax `m _` is deprecated.
74+
75+
## Reference
76+
77+
For more information, see [PR #2701](https://github.com/lampepfl/dotty/pull/2701).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
layout: doc-page
3+
title: "Automatic Eta Expansion"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/eta-expansion.html
5+
---
6+
7+
The conversion of _methods_ into _functions_ has been improved and happens automatically for methods with one or more parameters.
8+
9+
```scala
10+
def m(x: Boolean, y: String)(z: Int): List[Int]
11+
val f1 = m
12+
val f2 = m(true, "abc")
13+
```
14+
15+
This creates two function values:
16+
```scala
17+
f1: (Boolean, String) => Int => List[Int]
18+
f2: Int => List[Int]
19+
```
20+
21+
The syntax `m _` is no longer needed and will be deprecated in the future.
22+
23+
## Automatic eta-expansion and nullary methods
24+
25+
Automatic eta expansion does not apply to "nullary" methods that take an empty parameter list.
26+
27+
```scala
28+
def next(): T
29+
```
30+
31+
Given a simple reference to `next` does not auto-convert to a function.
32+
One has to write explicitly `() => next()` to achieve that.
33+
Once again since the `_` is going to be deprecated it's better to write it this way
34+
rather than `next _`.
35+
36+
The reason for excluding nullary methods from automatic eta expansion
37+
is that Scala implicitly inserts the `()` argument, which would
38+
conflict with eta expansion. Automatic `()` insertion is
39+
[limited](../dropped-features/auto-apply.md) in Scala 3, but the fundamental ambiguity
40+
remains.
41+
42+
[More details](eta-expansion-spec.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
layout: doc-page
3+
title: "Implicit Conversions - More Details"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/changed-features/implicit-conversions-spec.html
5+
---
6+
7+
## Implementation
8+
9+
An implicit conversion, or _view_, from type `S` to type `T` is
10+
defined by either:
11+
12+
- An `implicit def` which has type `S => T` or `(=> S) => T`
13+
- An implicit value which has type `Conversion[S, T]`
14+
15+
The standard library defines an abstract class [`Conversion`](https://scala-lang.org/api/3.x/scala/Conversion.html):
16+
17+
```scala
18+
package scala
19+
@java.lang.FunctionalInterface
20+
abstract class Conversion[-T, +U] extends Function1[T, U]:
21+
def apply(x: T): U
22+
```
23+
24+
Function literals are automatically converted to `Conversion` values.
25+
26+
Views are applied in three situations:
27+
28+
1. If an expression `e` is of type `T`, and `T` does not conform to
29+
the expression's expected type `pt`. In this case, an implicit `v`
30+
which is applicable to `e` and whose result type conforms to `pt`
31+
is searched. The search proceeds as in the case of implicit
32+
parameters, where the implicit scope is the one of `T => pt`. If
33+
such a view is found, the expression `e` is converted to `v(e)`.
34+
1. In a selection `e.m` with `e` of type `T`, if the selector `m` does
35+
not denote an accessible member of `T`. In this case, a view `v`
36+
which is applicable to `e` and whose result contains an accessible
37+
member named `m` is searched. The search proceeds as in the case of
38+
implicit parameters, where the implicit scope is the one of `T`. If
39+
such a view is found, the selection `e.m` is converted to `v(e).m`.
40+
1. In an application `e.m(args)` with `e` of type `T`, if the selector
41+
`m` denotes some accessible member(s) of `T`, but none of these
42+
members is applicable to the arguments `args`. In this case, a view
43+
`v` which is applicable to `e` and whose result contains a method
44+
`m` which is applicable to `args` is searched. The search proceeds
45+
as in the case of implicit parameters, where the implicit scope is
46+
the one of `T`. If such a view is found, the application
47+
`e.m(args)` is converted to `v(e).m(args)`.
48+
49+
# Differences with Scala 2 implicit conversions
50+
51+
In Scala 2, views whose parameters are passed by-value take precedence
52+
over views whose parameters are passed by-name. This is no longer the
53+
case in Scala 3. A type error reporting the ambiguous conversions will
54+
be emitted in cases where this rule would be applied in Scala 2:
55+
56+
```scala
57+
implicit def conv1(x: Int): String = x.toString
58+
implicit def conv2(x: => Int): String = x.toString
59+
60+
val x: String = 0 // Compiles in Scala2 (uses `conv1`),
61+
// type error in Scala 3 because of ambiguity.
62+
```
63+
64+
In Scala 2, implicit values of a function type would be considered as
65+
potential views. In Scala 3, these implicit value need to have type
66+
`Conversion`:
67+
68+
```scala
69+
// Scala 2:
70+
def foo(x: Int)(implicit conv: Int => String): String = x
71+
72+
// Becomes with Scala 3:
73+
def foo(x: Int)(implicit conv: Conversion[Int, String]): String = x
74+
75+
// Call site is unchanged:
76+
foo(4)(_.toString)
77+
78+
// Scala 2:
79+
implicit val myConverter: Int => String = _.toString
80+
81+
// Becomes with Scala 3:
82+
implicit val myConverter: Conversion[Int, String] = _.toString
83+
```
84+
85+
Note that implicit conversions are also affected by the [changes to implicit resolution](implicit-resolution.md) between Scala 2 and Scala 3.
86+
87+
## Motivation for the changes
88+
89+
The introduction of [`scala.Conversion`](https://scala-lang.org/api/3.x/scala/Conversion.html)
90+
in Scala 3 and the decision to restrict implicit values of this type to be
91+
considered as potential views comes from the desire to remove surprising
92+
behavior from the language:
93+
94+
```scala
95+
implicit val m: Map[Int, String] = Map(1 -> "abc")
96+
97+
val x: String = 1 // Scala 2: assigns "abc" to x
98+
// Scala 3: type error
99+
```
100+
101+
This snippet contains a type error. The right-hand side of `val x`
102+
does not conform to type `String`. In Scala 2, the compiler will use
103+
`m` as an implicit conversion from `Int` to `String`, whereas Scala 3
104+
will report a type error, because `Map` isn't an instance of
105+
[`Conversion`](https://scala-lang.org/api/3.x/scala/Conversion.html).
106+
107+
## Migration path
108+
109+
Implicit values that are used as views should see their type changed to `Conversion`.
110+
111+
For the migration of implicit conversions that are affected by the
112+
changes to implicit resolution, refer to the [Changes in Implicit Resolution](implicit-resolution.md) for more information.
113+
114+
## Reference
115+
116+
For more information about implicit resolution, see [Changes in Implicit Resolution](implicit-resolution.md).
117+
Other details are available in [PR #2065](https://github.com/lampepfl/dotty/pull/2065).

0 commit comments

Comments
 (0)