Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use =>> for type lambdas #6558

Merged
merged 2 commits into from
May 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -819,13 +819,13 @@ object desugar {

/** Expand
*
* <mods> opaque type T = [Xs] => R
* <mods> opaque type T = [Xs] =>> R
*
* to
*
* <mods> opaque type T = T.T
* synthetic object T {
* synthetic opaque type T >: [Xs] => R
* synthetic opaque type T >: [Xs] =>> R
* }
*
* The generated companion object will later (in Namer) be merged with the user-defined
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ object Parsers {
def toplevelTyp(): Tree = rejectWildcardType(typ())

/** Type ::= FunTypeMods FunArgTypes `=>' Type
* | HkTypeParamClause `->' Type
* | HkTypeParamClause `=>>' Type
* | InfixType
* FunArgTypes ::= InfixType
* | `(' [ FunArgType {`,' FunArgType } ] `)'
Expand Down Expand Up @@ -922,9 +922,9 @@ object Parsers {
else if (in.token == LBRACKET) {
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
if (in.token == ARROW)
if (in.token == TLARROW)
atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
else { accept(ARROW); typ() }
else { accept(TLARROW); typ() }
}
else infixType()

Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/parsing/Tokens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,15 @@ object Tokens extends TokensCommon {
final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
final val HASH = 82; enter(HASH, "#")
final val VIEWBOUND = 84; enter(VIEWBOUND, "<%")
final val QUOTE = 85; enter(QUOTE, "'")
final val TLARROW = 85; enter(TLARROW, "=>>")

final val QUOTE = 86; enter(QUOTE, "'")

/** XML mode */
final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate

final val alphaKeywords: TokenSet = tokenRange(IF, MACRO)
final val symbolicKeywords: TokenSet = tokenRange(USCORE, VIEWBOUND)
milessabin marked this conversation as resolved.
Show resolved Hide resolved
final val symbolicKeywords: TokenSet = tokenRange(USCORE, TLARROW)
final val keywords: TokenSet = alphaKeywords | symbolicKeywords

final val allTokens: TokenSet = tokenRange(minToken, maxToken)
Expand Down
6 changes: 3 additions & 3 deletions compiler/test-resources/repl/i6474
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
scala> object Foo1 { type T[+A] = (A, Int) }
// defined object Foo1
scala> object Foo2 { type T[+A] = [+B] => (A, B) }
scala> object Foo2 { type T[+A] = [+B] =>> (A, B) }
// defined object Foo2
scala> object Foo3 { type T[+A] = [+B] => [C] => (A, B) }
scala> object Foo3 { type T[+A] = [+B] =>> [C] =>> (A, B) }
// defined object Foo3
scala> ((1, 2): Foo1.T[Int]): Foo1.T[Any]
val res0: (Any, Int) = (1,2)
Expand All @@ -14,7 +14,7 @@ scala> (1, 2): Foo3.T[Int][Int]
| Missing type parameter for Foo3.T[Int][Int]
scala> ((1, 2): Foo3.T[Int][Int][Int]): Foo3.T[Any][Int][Int]
val res2: (Any, Int) = (1,2)
scala> object Foo3 { type T[A] = [B] => [C] => (A, B) }
scala> object Foo3 { type T[A] = [B] =>> [C] =>> (A, B) }
// defined object Foo3
scala> ((1, 2): Foo3.T[Int][Int][Int])
val res3: (Int, Int) = (1,2)
Expand Down
6 changes: 3 additions & 3 deletions docs/blog/_posts/2018-04-27-eighth-dotty-milestone-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ def foo[T](x: T) = x match {
Normally type parameters in Scala are partitioned into kinds. First-level types are types of values.
Higher-kinded types are type constructors such as `List` or `Map`. The kind of a type is indicated
by the top type of which it is a subtype. Normal types are subtypes of `Any`, covariant single
argument type constructors such as List are subtypes of `[+X] => Any`, and the `Map` type
constructor is a subtype of `[X, +Y] => Any`.
argument type constructors such as List are subtypes of `[+X] =>> Any`, and the `Map` type
constructor is a subtype of `[X, +Y] =>> Any`.

Sometimes we would like to have type parameters that can have more than one kind, for instance to
define an implicit value that works for parameters of any kind. This is now possible through a form
Expand All @@ -87,7 +87,7 @@ legal:
f[Int]
f[List]
f[Map]
f[[X] => String]
f[[X] =>> String]
```

**Note**: This feature is considered experimental and is only enabled under a compiler flag
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ package private protected override return super sealed then
throw trait true try type val var while
with yield
: = <- => <: :> # @
=>>
```

### Soft keywords
Expand Down Expand Up @@ -139,7 +140,7 @@ ClassQualifier ::= ‘[’ id ‘]’
### Types
```ebnf
Type ::= { ‘erased’ | ‘given’} FunArgTypes ‘=>’ Type Function(ts, t)
| HkTypeParamClause ‘=>’ Type TypeLambda(ps, t)
| HkTypeParamClause ‘=>>’ Type TypeLambda(ps, t)
| MatchType
| InfixType
FunArgTypes ::= InfixType
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/contextual/typeclasses.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ implied ListMonad for Monad[List] {
List(x)
}

implied ReaderMonad[Ctx] for Monad[[X] => Ctx => X] {
implied ReaderMonad[Ctx] for Monad[[X] =>> Ctx => X] {
def (r: Ctx => A) flatMap [A, B] (f: A => Ctx => B): Ctx => B =
ctx => f(r(ctx))(ctx)
def pure[A](x: A): Ctx => A =
Expand Down
28 changes: 14 additions & 14 deletions docs/docs/reference/new-types/type-lambdas-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ title: "Type Lambdas - More Details"
## Syntax

```
Type ::= ... | HkTypeParamClause ‘=>’ Type
Type ::= ... | HkTypeParamClause ‘=>>’ Type
HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] | ‘_’) TypeBounds
TypeBounds ::= [‘>:’ Type] [‘<:’ Type]
```

### Type Checking

A type lambda such `[X] => F[X]` defines a function from types to types. The parameter(s) may carry bounds and variance annotations.
If a parameter is is bounded, as in `[X >: L <: H] => F[X]` it is checked that arguments to the parameters conform to the bounds `L` and `H`.
A type lambda such `[X] =>> F[X]` defines a function from types to types. The parameter(s) may carry bounds and variance annotations.
If a parameter is is bounded, as in `[X >: L <: H] =>> F[X]` it is checked that arguments to the parameters conform to the bounds `L` and `H`.
Only the upper bound `H` can be F-bounded, i.e. `X` can appear in it.

A variance annotation on a parameter indicates a subtyping relationship on type instances. For instance, given
```scala
type TL1 = [+A] => F[A]
type TL2 = [-A] => F[A]
type TL1 = [+A] =>> F[A]
type TL2 = [-A] =>> F[A]
```
and two types `S <: T`, we have
```scala
Expand All @@ -37,8 +37,8 @@ It is checked that variance annotations on parameters of type lambdas are respec

Assume two type lambdas
```scala
type TL1 = [v1 X >: L1 <: U1] => R1
type TL2 = [v2 X >: L2 <: U2] => R2
type TL1 = [v1 X >: L1 <: U1] =>> R1
type TL2 = [v2 X >: L2 <: U2] =>> R2
```
where `v1` and `v2` are optional variance annotations: `+`, `-`, or absent.
Then `TL1 <: TL2`, if
Expand All @@ -51,7 +51,7 @@ Then `TL1 <: TL2`, if
Here we have relied on alpha renaming to bring match the two bound types `X`.

A partially applied type constructor such as `List` is assumed to be equivalent to
its eta expansion. I.e, `List = [+X] => List[X]`. This allows type constructors
its eta expansion. I.e, `List = [+X] =>> List[X]`. This allows type constructors
to be compared with type lambdas.

## Relationship with Parameterized Type Definitions
Expand All @@ -62,7 +62,7 @@ type T[X] = R
```
is regarded as a shorthand for an unparameterized definition with a type lambda as right-hand side:
```scala
type T = [X] => R
type T = [X] =>> R
```

A parameterized abstract type
Expand All @@ -71,19 +71,19 @@ type T[X] >: L <: U
```
is regarded as shorthand for an unparameterized abstract type with type lambdas as bounds.
```scala
type T >: ([X] => L) <: ([X] => U)
type T >: ([X] =>> L) <: ([X] =>> U)
```
However, if `L` is `Nothing` it is not parameterized, since `Nothing` is treated as a bottom type for all kinds. For instance,
```scala
type T[-X] <: X => ()
```
is expanded to
```scala
type T >: Nothing <: ([-X] => X => ())
type T >: Nothing <: ([-X] =>> X => ())
```
instead of
```scala
type T >: ([X] => Nothing) <: ([-X] => X => ())
type T >: ([X] =>> Nothing) <: ([-X] =>> X => ())
```

The same expansions apply to type parameters. E.g.
Expand All @@ -92,7 +92,7 @@ The same expansions apply to type parameters. E.g.
```
is treated as a shorthand for
```scala
[F >: Nothing <: [X] => Coll[X]]
[F >: Nothing <: [X] =>> Coll[X]]
```

**Note**: The decision to treat `Nothing` as universal bottom type is provisional, and might be changed afer further discussion.
Expand All @@ -103,7 +103,7 @@ is treated as a shorthand for

The body of a type lambda can again be a type lambda. Example:
```scala
type TL = [X] => [Y] => (X, Y)
type TL = [X] =>> [Y] =>> (X, Y)
```
Currently, no special provision is made to infer type arguments to such curried type lambdas. This is left for future work.

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/new-types/type-lambdas.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ title: "Type Lambdas"
A _type lambda_ lets one express a higher-kinded type directly, without
a type definition.

[+X, Y] => Map[Y, X]
[+X, Y] =>> Map[Y, X]

For instance, the type above defines a binary type constructor, with a
covariant parameter `X` and a non-variant parameter `Y`. The
Expand All @@ -19,6 +19,6 @@ definition or declaration such as
is a shorthand for a plain type definition with a type-lambda as its
right-hand side:

type T = [X] => (X, X)
type T = [X] =>> (X, X)

[More details](./type-lambdas-spec.html)
8 changes: 4 additions & 4 deletions docs/docs/reference/other-new-features/kind-polymorphism.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ title: "Kind Polymorphism"

Normally type parameters in Scala are partitioned into _kinds_. First-level types are types of values. Higher-kinded types are type constructors
such as `List` or `Map`. The kind of a type is indicated by the top type of which it is a subtype. Normal types are subtypes of `Any`,
covariant single argument type constructors such as `List` are subtypes of `[+X] => Any`, and the `Map` type constructor is
a subtype of `[X, +Y] => Any`.
covariant single argument type constructors such as `List` are subtypes of `[+X] =>> Any`, and the `Map` type constructor is
a subtype of `[X, +Y] =>> Any`.

A type can be used only as prescribed by its kind. Subtypes of `Any` cannot be applied to type arguments whereas subtypes of `[X] => Any`
A type can be used only as prescribed by its kind. Subtypes of `Any` cannot be applied to type arguments whereas subtypes of `[X] =>> Any`
_must_ be applied to a type argument, unless they are passed to type parameters of the same kind.

Sometimes we would like to have type parameters that can have more than one kind, for instance to define an implicit
Expand All @@ -25,7 +25,7 @@ The actual type arguments of `f` can then be types of arbitrary kinds. So the fo
f[Int]
f[List]
f[Map]
f[[X] => String]
f[[X] =>> String]
```

We call type parameters and abstract types with an `AnyKind` upper bound _any-kinded types_`.
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/anykind.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object AnyKinds {
}

f[Int] // OK
f[[X] => X] // OK
f[[X] =>> X] // OK
f[Nothing] // OK

def g[X <: Any]: Any = {
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/anykind2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ object AnyKinds {
}

f[Int] // OK
f[[X] => X] // OK
f[[X] =>> X] // OK
f[Nothing] // OK

def g[X <: Any]: Any = {
Expand Down
10 changes: 5 additions & 5 deletions tests/neg/enum-tparams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ object Test {
type Id[_]

enum E[F[_], G[_]] {
case C1() extends E[[X] => X, Id]
case C2() extends E[[F] => F, Id]
case C3() extends E[[X] => { type Y = F[Int] }, Id]
case C4() extends E[[X] => { type F = Int }, Id]
case C5() extends E[[F] => G[Int], Id]
case C1() extends E[[X] =>> X, Id]
case C2() extends E[[F] =>> F, Id]
case C3() extends E[[X] =>> { type Y = F[Int] }, Id]
case C4() extends E[[X] =>> { type F = Int }, Id]
case C5() extends E[[F] =>> G[Int], Id]
}

Opt.S[Int](1) // OK
Expand Down
12 changes: 6 additions & 6 deletions tests/neg/existentials.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
object TestList {

var x: ([X] => List[List[X]])[_] = List(List(1)) // error: unreducible
var y: ([X] => List[Seq[X]])[_] = List(List(1)) // error: unreducible
var x: ([X] =>> List[List[X]])[_] = List(List(1)) // error: unreducible
var y: ([X] =>> List[Seq[X]])[_] = List(List(1)) // error: unreducible

x = x
y = y
Expand All @@ -15,8 +15,8 @@ object TestList {
}
object TestSet {

var x: ([Y] => Set[Set[Y]])[_] = Set(Set("a")) // error: unreducible
var y: ([Y] => Set[Iterable[Y]])[_] = Set(Set("a")) // error: unreducible
var x: ([Y] =>> Set[Set[Y]])[_] = Set(Set("a")) // error: unreducible
var y: ([Y] =>> Set[Iterable[Y]])[_] = Set(Set("a")) // error: unreducible

x = x
y = y
Expand All @@ -36,14 +36,14 @@ class TestX {
def cmp: T => Boolean = (x == _)
}

val x: ([Y] => C[C[Y]])[_] = new C(new C("a")) // error: unreducible
val x: ([Y] =>> C[C[Y]])[_] = new C(new C("a")) // error: unreducible

type CC[X] = C[C[X]]
val y: CC[_] = ??? // error: unreducible

type D[X] <: C[X]

type DD = [X] => D[D[X]]
type DD = [X] =>> D[D[X]]
val z: DD[_] = ??? // error: unreducible

val g = x.get
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i1181c.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This program compiles with Dotty using refined types for application, but
// does not compile with native applications. The reason is that in previous
// Dotty the parameter reference to the lambda [X, Y] => Foo[X, Y] was a TypeRef
// Dotty the parameter reference to the lambda [X, Y] =>> Foo[X, Y] was a TypeRef
// which could be selected for partial application. But now the type lambda gets
// substituted directly, which prevents that conversion. The program compiles
// if the type lambda is replaced by a type alias (see pos/i1181c.scala).
Expand All @@ -13,7 +13,7 @@ trait Bar[DD[_,_]] {
object Test {
type F[X, Y] = Foo[X]

trait Baz extends Bar[[X,Y] => Foo[X]] {
trait Baz extends Bar[[X,Y] =>> Foo[X]] {
def foo[M[_,_]](x: M[Int, Int]) = x

foo(x) // error: found: Foo[Int](Baz.this.x) required: M[Int, Int]
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i2151.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
trait Test {
type Nil = [K] => K
type StrangeCons[H, Tail <: [H, A] => H] = Tail[H, H]
type Nil = [K] =>> K
type StrangeCons[H, Tail <: [H, A] =>> H] = Tail[H, H]

def list: StrangeCons[Int, Nil] // error
}
4 changes: 2 additions & 2 deletions tests/neg/i2232.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ object Cats {
implicit def trivial[A]: Trivial[A] = new Trivial[A] { }

type Obj[C[_[_[_], _[_, _]]]] =
[A] => C[({type l[c0[_], c1[_, _]] = c0[A] })#l]
[A] =>> C[({type l[c0[_], c1[_, _]] = c0[A] })#l]
type Cat[C[_[_[_], _[_, _]]]] =
[A, B] => C[({type l[c0[_], c1[_, _]] = c1[A, B]})#l]
[A, B] =>> C[({type l[c0[_], c1[_, _]] = c1[A, B]})#l]

trait Category[C[_[_[_], _[_, _]]]] {
type -> = Cats.Cat[C]
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i3452.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ object Test {

trait TC[A]

implicit def case1[F[_]](implicit t: => TC[F[Any]]): TC[Tuple2K[[_] => Any, F, Any]] = ???
implicit def case1[F[_]](implicit t: => TC[F[Any]]): TC[Tuple2K[[_] =>> Any, F, Any]] = ???
implicit def case2[A, F[_]](implicit r: TC[F[Any]]): TC[A] = ???

implicitly[TC[Int]] // error
Expand Down
Loading