Skip to content

Commit 6db3a6c

Browse files
committed
Merge branch 'master' into type-class
# Conflicts: # docs/docs/reference/changed-features/numeric-literals.md
2 parents 972f809 + 5e9d927 commit 6db3a6c

File tree

18 files changed

+145
-57
lines changed

18 files changed

+145
-57
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,6 @@
9494
[submodule "community-build/community-projects/scalaz"]
9595
path = community-build/community-projects/scalaz
9696
url = https://github.com/dotty-staging/scalaz.git
97+
[submodule "community-build/community-projects/endpoints"]
98+
path = community-build/community-projects/endpoints
99+
url = https://github.com/dotty-staging/endpoints.git
Submodule endpoints added at e52dbb1

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,11 @@ object projects:
284284
dependencies = List(scalacheck)
285285
)
286286

287+
lazy val endpoints = SbtCommunityProject(
288+
project = "endpoints",
289+
sbtTestCommand = ";json-schemaJVM/compile;algebraJVM/compile;openapiJVM/compile;http4s-server/compile;http4s-client/compile;play-server/compile;play-client/compile;akka-http-server/compile;akka-http-client/compile"
290+
)
291+
287292
end projects
288293

289294
@Category(Array(classOf[TestCategory]))
@@ -376,6 +381,7 @@ class CommunityBuildTest:
376381
@Test def scalaParserCombinators = projects.scalaParserCombinators.run()
377382
@Test def dottyCpsAsync = projects.dottyCpsAsync.run()
378383
@Test def scalaz = projects.scalaz.run()
384+
@Test def endpoints = projects.endpoints.run()
379385
end CommunityBuildTest
380386

381387
class TestCategory

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,16 +1347,53 @@ trait Applications extends Compatibility {
13471347
* @return 1 if `sym1` properly derives from `sym2`
13481348
* -1 if `sym2` properly derives from `sym1`
13491349
* 0 otherwise
1350-
* Module classes also inherit the relationship from their companions.
1350+
* Module classes also inherit the relationship from their companions. This means,
1351+
* if no direct derivation exists between `sym1` and `sym2` also perform the following
1352+
* tests:
1353+
* - If both sym1 and sym1 are module classes that have companion classes, compare the companions
1354+
* - If sym1 is a module class with a companion, and sym2 is a normal class or trait, compare
1355+
* the companion with sym2.
1356+
*
1357+
* Note that this makes `compareOwner(_, _) > 0` not transitive! For instance:
1358+
*
1359+
* class A extends B
1360+
* object A
1361+
* class B
1362+
* object B extends C
1363+
*
1364+
* Then compareOwner(A$, B$) = 1 and compareOwner(B$, C) == 1, but
1365+
* compareOwner(A$, C) == 0.
13511366
*/
13521367
def compareOwner(sym1: Symbol, sym2: Symbol)(using Context): Int =
1353-
if (sym1 == sym2) 0
1354-
else if (sym1 isSubClass sym2) 1
1355-
else if (sym2 isSubClass sym1) -1
1356-
else if (sym2.is(Module)) compareOwner(sym1, sym2.companionClass)
1357-
else if (sym1.is(Module)) compareOwner(sym1.companionClass, sym2)
1368+
if sym1 == sym2 then 0
1369+
else if sym1.isSubClass(sym2) then 1
1370+
else if sym2.isSubClass(sym1) then -1
1371+
else if sym1.is(Module) then
1372+
compareOwner(sym1.companionClass, if sym2.is(Module) then sym2.companionClass else sym2)
13581373
else 0
13591374

1375+
/** A version of `compareOwner` that is transitive, to be used in sorting
1376+
* It would be nice if we could use this as the general method for comparing
1377+
* owners, but unfortunately this does not compile all existsing code.
1378+
* An example is `enrich-gentraversable.scala`. Here we have
1379+
*
1380+
* trait BuildFrom...
1381+
* object BuildFrom extends BuildFromLowPriority1
1382+
*
1383+
* and we need to pick an implicit in BuildFrom over BuildFromLowPriority1
1384+
* the rules in `compareOwner` give us that, but the rules in `isSubOwner`
1385+
* don't.
1386+
* So we need to stick with `compareOwner` for backwards compatibility, even
1387+
* though it is arguably broken. We can still use `isSubOwner` for sorting
1388+
* since that is just a performance optimization, so if the two methods
1389+
* don't agree sometimes that's OK.
1390+
*/
1391+
def isSubOwner(sym1: Symbol, sym2: Symbol)(using Context): Boolean =
1392+
if sym1.is(Module) && sym1.companionClass.exists then
1393+
isSubOwner(sym1.companionClass, if sym2.is(Module) then sym2.companionClass else sym2)
1394+
else
1395+
sym1 != sym2 && sym1.isSubClass(sym2)
1396+
13601397
/** Compare to alternatives of an overloaded call or an implicit search.
13611398
*
13621399
* @param alt1, alt2 Non-overloaded references indicating the two choices

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,14 +1169,11 @@ trait Implicits { self: Typer =>
11691169
if (level1 < level2) return false
11701170
val sym1 = cand1.ref.symbol
11711171
val sym2 = cand2.ref.symbol
1172-
val ownerScore = compareOwner(sym1.maybeOwner, sym2.maybeOwner)
1173-
if (ownerScore > 0) return true
1174-
if (ownerScore < 0) return false
11751172
val arity1 = sym1.info.firstParamTypes.length
11761173
val arity2 = sym2.info.firstParamTypes.length
11771174
if (arity1 < arity2) return true
11781175
if (arity1 > arity2) return false
1179-
false
1176+
isSubOwner(sym1, sym2)
11801177
}
11811178

11821179
/** Sort list of implicit references according to `prefer`.
@@ -1190,7 +1187,19 @@ trait Implicits { self: Typer =>
11901187
if (prefer(e2, e1)) e2 :: e1 :: Nil
11911188
else eligible
11921189
case _ =>
1193-
eligible.sortWith(prefer)
1190+
try eligible.sortWith(prefer)
1191+
catch case ex: IllegalArgumentException =>
1192+
// diagnostic to see what went wrong
1193+
for
1194+
e1 <- eligible
1195+
e2 <- eligible
1196+
if prefer(e1, e2)
1197+
e3 <- eligible
1198+
if prefer(e2, e3) && !prefer(e1, e3)
1199+
do
1200+
val es = List(e1, e2, e3)
1201+
println(i"transitivity violated for $es%, %\n ${es.map(_.implicitRef.underlyingRef.symbol.showLocated)}%, %")
1202+
throw ex
11941203
}
11951204

11961205
rank(sort(eligible), NoMatchingImplicitsFailure, Nil)

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
12191219
super.typedIf(if1, pt)
12201220
}
12211221

1222+
override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
1223+
val vdef1 =
1224+
if sym.is(Inline) then
1225+
val rhs = typed(vdef.rhs)
1226+
sym.info = rhs.tpe
1227+
untpd.cpy.ValDef(vdef)(vdef.name, untpd.TypeTree(rhs.tpe), untpd.TypedSplice(rhs))
1228+
else vdef
1229+
super.typedValDef(vdef1, sym)
1230+
12221231
override def typedApply(tree: untpd.Apply, pt: Type)(using Context): Tree =
12231232
constToLiteral(betaReduce(super.typedApply(tree, pt))) match {
12241233
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice

docs/docs/reference/changed-features/implicit-resolution.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: doc-page
33
title: "Changes in Implicit Resolution"
44
---
5-
5+
This page describes changes to the implicit resolution that apply both to the new `given`s and to the old-style `implicit`s in Dotty.
66
Implicit resolution uses a new algorithm which caches implicit results
77
more aggressively for performance. There are also some changes that
88
affect implicits on the language level.
@@ -39,7 +39,7 @@ affect implicits on the language level.
3939
due to _shadowing_ (where an implicit is hidden by a nested definition)
4040
no longer applies.
4141

42-
3. Package prefixes no longer contribute to the implicit scope of a type.
42+
3. Package prefixes no longer contribute to the implicit search scope of a type.
4343
Example:
4444
```scala
4545
package p
@@ -52,7 +52,7 @@ affect implicits on the language level.
5252
```
5353
Both `a` and `b` are visible as implicits at the point of the definition
5454
of `type C`. However, a reference to `p.o.C` outside of package `p` will
55-
have only `b` in its implicit scope but not `a`.
55+
have only `b` in its implicit search scope but not `a`.
5656

5757
4. The treatment of ambiguity errors has changed. If an ambiguity is encountered
5858
in some recursive step of an implicit search, the ambiguity is propagated to the caller.
@@ -85,7 +85,7 @@ affect implicits on the language level.
8585
5. The treatment of divergence errors has also changed. A divergent implicit is
8686
treated as a normal failure, after which alternatives are still tried. This also makes
8787
sense: Encountering a divergent implicit means that we assume that no finite
88-
solution can be found on the given path, but another path can still be tried. By contrast
88+
solution can be found on the corresponding path, but another path can still be tried. By contrast
8989
most (but not all) divergence errors in Scala 2 would terminate the implicit
9090
search as a whole.
9191

docs/docs/reference/changed-features/numeric-literals.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ val x = -10_000_000_000
5252
```
5353
gives a type error, since without an expected type `-10_000_000_000` is treated by rule (3) as an `Int` literal, but it is too large for that type.
5454

55-
### The FromDigits Class
55+
### The FromDigits Trait
5656

57-
To allow numeric literals, a type simply has to define a given instance of the
57+
To allow numeric literals, a type simply has to define a `given` instance of the
5858
`scala.util.FromDigits` type class, or one of its subclasses. `FromDigits` is defined
5959
as follows:
6060
```scala
@@ -153,7 +153,7 @@ object BigFloat {
153153
BigFloat(BigInt(intPart), exponent)
154154
}
155155
```
156-
To accept `BigFloat` literals, all that's needed in addition is a given instance of type
156+
To accept `BigFloat` literals, all that's needed in addition is a `given` instance of type
157157
`FromDigits.Floating[BigFloat]`:
158158
```scala
159159
given FromDigits as FromDigits.Floating[BigFloat] {
@@ -196,7 +196,7 @@ object BigFloat {
196196
}
197197
```
198198
Note that an inline method cannot directly fill in for an abstract method, since it produces
199-
no code that can be executed at runtime. That's why we define an intermediary class
199+
no code that can be executed at runtime. That is why we define an intermediary class
200200
`FromDigits` that contains a fallback implementation which is then overridden by the inline
201201
method in the `FromDigits` given instance. That method is defined in terms of a macro
202202
implementation method `fromDigitsImpl`. Here is its definition:
@@ -220,7 +220,7 @@ implementation method `fromDigitsImpl`. Here is its definition:
220220
```
221221
The macro implementation takes an argument of type `Expr[String]` and yields
222222
a result of type `Expr[BigFloat]`. It tests whether its argument is a constant
223-
string. If that's the case, it converts the string using the `apply` method
223+
string. If that is the case, it converts the string using the `apply` method
224224
and lifts the resulting `BigFloat` back to `Expr` level. For non-constant
225225
strings `fromDigitsImpl(digits)` is simply `apply(digits)`, i.e. everything is
226226
evaluated at runtime in this case.

docs/docs/reference/contextual/multiversal-equality.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,19 @@ given Eql[B, A] = Eql.derived
6767
The `scala.Eql` object defines a number of `Eql` given instances that together
6868
define a rule book for what standard types can be compared (more details below).
6969

70-
There's also a "fallback" instance named `eqlAny` that allows comparisons
70+
There is also a "fallback" instance named `eqlAny` that allows comparisons
7171
over all types that do not themselves have an `Eql` given. `eqlAny` is defined as follows:
7272

7373
```scala
7474
def eqlAny[L, R]: Eql[L, R] = Eql.derived
7575
```
7676

77-
Even though `eqlAny` is not declared a given, the compiler will still construct an `eqlAny` instance as answer to an implicit search for the
77+
Even though `eqlAny` is not declared as `given`, the compiler will still construct an `eqlAny` instance as answer to an implicit search for the
7878
type `Eql[L, R]`, unless `L` or `R` have `Eql` instances
79-
defined on them, or the language feature `strictEquality` is enabled
79+
defined on them, or the language feature `strictEquality` is enabled.
8080

81-
The primary motivation for having `eqlAny` is backwards compatibility,
82-
if this is of no concern, one can disable `eqlAny` by enabling the language
81+
The primary motivation for having `eqlAny` is backwards compatibility.
82+
If this is of no concern, one can disable `eqlAny` by enabling the language
8383
feature `strictEquality`. As for all language features this can be either
8484
done with an import
8585

@@ -112,7 +112,7 @@ The precise rules for equality checking are as follows.
112112

113113
If the `strictEquality` feature is enabled then
114114
a comparison using `x == y` or `x != y` between values `x: T` and `y: U`
115-
is legal if there is a given of type `Eql[T, U]`.
115+
is legal if there is a `given` of type `Eql[T, U]`.
116116

117117
In the default case where the `strictEquality` feature is not enabled the comparison is
118118
also legal if
@@ -123,8 +123,8 @@ also legal if
123123

124124
Explanations:
125125

126-
- _lifting_ a type `S` means replacing all references to abstract types
127-
in covariant positions of `S` by their upper bound, and to replacing
126+
- _lifting_ a type `S` means replacing all references to abstract types
127+
in covariant positions of `S` by their upper bound, and replacing
128128
all refinement types in covariant positions of `S` by their parent.
129129
- a type `T` has a _reflexive_ `Eql` instance if the implicit search for `Eql[T, T]`
130130
succeeds.
@@ -153,8 +153,9 @@ Instances are defined so that every one of these types has a _reflexive_ `Eql` i
153153
## Why Two Type Parameters?
154154

155155
One particular feature of the `Eql` type is that it takes _two_ type parameters, representing the types of the two items to be compared. By contrast, conventional
156-
implementations of an equality type class take only a single type parameter which represents the common type of _both_ operands. One type parameter is simpler than two, so why go through the additional complication? The reason has to do with the fact that, rather than coming up with a type class where no operation existed before,
157-
we are dealing with a refinement of pre-existing, universal equality. It's best illustrated through an example.
156+
implementations of an equality type class take only a single type parameter which represents the common type of _both_ operands.
157+
One type parameter is simpler than two, so why go through the additional complication? The reason has to do with the fact that, rather than coming up with a type class where no operation existed before,
158+
we are dealing with a refinement of pre-existing, universal equality. It is best illustrated through an example.
158159

159160
Say you want to come up with a safe version of the `contains` method on `List[T]`. The original definition of `contains` in the standard library was:
160161
```scala

docs/docs/reference/metaprogramming/tasty-inspect.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ libraryDependencies += "ch.epfl.lamp" %% "dotty-tasty-inspector" % scalaVersion.
99

1010
TASTy files contain the full typed tree of a class including source positions
1111
and documentation. This is ideal for tools that analyze or extract semantic
12-
information of the code. To avoid the hassle of working directly with the TASTy
12+
information from the code. To avoid the hassle of working directly with the TASTy
1313
file we provide the `TastyInspector` which loads the contents and exposes it
1414
through the TASTy reflect API.
1515

@@ -42,8 +42,8 @@ object Test {
4242
}
4343
```
4444

45-
Note that if we need to run the main (in an object called `Test`) after
46-
compilation we need make available the compiler to the runtime:
45+
Note that if we need to run the main (in the example below defined in an object called `Test`) after
46+
compilation we need to make the compiler available to the runtime:
4747

4848
```shell
4949
dotc -d out Test.scala

docs/docs/reference/metaprogramming/tasty-reflect.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ You may find all you need without using TASTy Reflect.
1414
## API: From quotes and splices to TASTy reflect trees and back
1515

1616
With `quoted.Expr` and `quoted.Type` we can compute code but also analyze code
17-
by inspecting the ASTs. [Macros](./macros.md) provides the guarantee that the
17+
by inspecting the ASTs. [Macros](./macros.md) provide the guarantee that the
1818
generation of code will be type-correct. Using TASTy Reflect will break these
1919
guarantees and may fail at macro expansion time, hence additional explicit
2020
checks must be done.
@@ -64,8 +64,7 @@ To easily know which extractors are needed, the `showExtractors` method on a
6464
The method `qctx.tasty.Term.seal` provides a way to go back to a
6565
`quoted.Expr[Any]`. Note that the type is `Expr[Any]`. Consequently, the type
6666
must be set explicitly with a checked `cast` call. If the type does not conform
67-
to it an exception will be thrown. In the code above, we could have replaced
68-
`Expr(n)` by `xTree.seal.cast[Int]`.
67+
to it an exception will be thrown at runtime.
6968

7069
### Obtaining the underlying argument
7170

@@ -92,8 +91,8 @@ macro(this.checkCondition())
9291

9392
### Positions
9493

95-
The tasty context provides a `rootPosition` value. For macros it corresponds to
96-
the expansion site. The macro authors can obtain various information about that
94+
The tasty context provides a `rootPosition` value. It corresponds to
95+
the expansion site for macros. The macro authors can obtain various information about that
9796
expansion site. The example below shows how we can obtain position information
9897
such as the start line, the end line or even the source code at the expansion
9998
point.
@@ -117,10 +116,10 @@ def macroImpl()(qctx: QuoteContext): Expr[Unit] = {
117116
### Tree Utilities
118117

119118
`scala.tasty.reflect` contains three facilities for tree traversal and
120-
transformations.
119+
transformation.
121120

122121
`TreeAccumulator` ties the knot of a traversal. By calling `foldOver(x, tree))`
123-
we can dive in the `tree` node and start accumulating values of type `X` (e.g.,
122+
we can dive into the `tree` node and start accumulating values of type `X` (e.g.,
124123
of type List[Symbol] if we want to collect symbols). The code below, for
125124
example, collects the pattern variables of a tree.
126125

@@ -142,8 +141,8 @@ but without returning any value. Finally a `TreeMap` performs a transformation.
142141
#### Let
143142

144143
`scala.tasty.Reflection` also offers a method `let` that allows us
145-
to bind the `rhs` to a `val` and use it in `body`. Additionally, `lets` binds
146-
the given `terms` to names and use them in the `body`. Their type definitions
144+
to bind the `rhs` (right-hand side) to a `val` and use it in `body`. Additionally, `lets` binds
145+
the given `terms` to names and allows to use them in the `body`. Their type definitions
147146
are shown below:
148147

149148
```scala

docs/docs/reference/new-types/intersection-types-spec.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ A & B <: B A & B <: A
4545
In another word, `A & B` is the same type as `B & A`, in the sense that the two types
4646
have the same values and are subtypes of each other.
4747

48-
If `C` is a type constructor, the join `C[A] & C[B]` is simplified by pulling the
49-
intersection inside the constructor, using the following two rules:
48+
If `C` is a type constructor, then `C[A] & C[B]` can be simplified using the following three rules:
5049

5150
- If `C` is covariant, `C[A] & C[B] ~> C[A & B]`
5251
- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]`
52+
- If `C` is non-variant, emit a compile error
5353

5454
When `C` is covariant, `C[A & B] <: C[A] & C[B]` can be derived:
5555

docs/docs/reference/new-types/intersection-types.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ The type `S & T` represents values that are of the type `S` and `T` at the same
1111

1212
```scala
1313
trait Resettable {
14-
def reset(): this.type
14+
def reset(): Unit
1515
}
1616
trait Growable[T] {
17-
def add(x: T): this.type
17+
def add(t: T): Unit
1818
}
1919
def f(x: Resettable & Growable[String]) = {
2020
x.reset()
2121
x.add("first")
2222
}
2323
```
2424

25-
The value `x` is required to be _both_ a `Resettable` and a
25+
The parameter `x` is required to be _both_ a `Resettable` and a
2626
`Growable[String]`.
2727

2828
The members of an intersection type `A & B` are all the members of `A` and all
@@ -51,8 +51,8 @@ can be further simplified to `List[A & B]` because `List` is
5151
covariant.
5252

5353
One might wonder how the compiler could come up with a definition for
54-
`children` of type `List[A & B]` since all its is given are `children`
55-
definitions of type `List[A]` and `List[B]`. The answer is it does not
54+
`children` of type `List[A & B]` since what is given are `children`
55+
definitions of type `List[A]` and `List[B]`. The answer is the compiler does not
5656
need to. `A & B` is just a type that represents a set of requirements for
5757
values of the type. At the point where a value is _constructed_, one
5858
must make sure that all inherited members are correctly defined.

0 commit comments

Comments
 (0)