Skip to content

Commit

Permalink
Merge pull request #4971 from adriaanm/genbcode-delambdafy
Browse files Browse the repository at this point in the history
Unify treatment of built-in functions and SAMs
  • Loading branch information
adriaanm committed Mar 31, 2016
2 parents 4fc7d55 + 5e5ab18 commit 5654ebd
Show file tree
Hide file tree
Showing 95 changed files with 1,739 additions and 1,452 deletions.
10 changes: 5 additions & 5 deletions build.sbt
Expand Up @@ -4,8 +4,8 @@
* What you see below is very much work-in-progress. The following features are implemented:
* - Compiling all classses for the compiler and library ("compile" in the respective subprojects)
* - Running JUnit tests ("test") and partest ("test/it:test")
* - Creating build-sbt/quick with all compiled classes and launcher scripts ("dist/mkQuick")
* - Creating build-sbt/pack with all JARs and launcher scripts ("dist/mkPack")
* - Creating build/quick with all compiled classes and launcher scripts ("dist/mkQuick")
* - Creating build/pack with all JARs and launcher scripts ("dist/mkPack")
* - Building all scaladoc sets ("doc")
* - Publishing ("publishDists" and standard sbt tasks like "publish" and "publishLocal")
*
Expand Down Expand Up @@ -722,8 +722,8 @@ def configureAsSubproject(project: Project): Project = {

lazy val buildDirectory = settingKey[File]("The directory where all build products go. By default ./build")
lazy val mkBin = taskKey[Seq[File]]("Generate shell script (bash or Windows batch).")
lazy val mkQuick = taskKey[Unit]("Generate a full build, including scripts, in build-sbt/quick")
lazy val mkPack = taskKey[Unit]("Generate a full build, including scripts, in build-sbt/pack")
lazy val mkQuick = taskKey[Unit]("Generate a full build, including scripts, in build/quick")
lazy val mkPack = taskKey[Unit]("Generate a full build, including scripts, in build/pack")

// Defining these settings is somewhat redundant as we also redefine settings that depend on them.
// However, IntelliJ's project import works better when these are set correctly.
Expand Down Expand Up @@ -782,7 +782,7 @@ def generateServiceProviderResources(services: (String, String)*): Setting[_] =
}
}.taskValue

buildDirectory in ThisBuild := (baseDirectory in ThisBuild).value / "build-sbt"
buildDirectory in ThisBuild := (baseDirectory in ThisBuild).value / "build"

// Add tab completion to partest
commands += Command("partest")(_ => PartestUtil.partestParser((baseDirectory in ThisBuild).value, (baseDirectory in ThisBuild).value / "test")) { (state, parsed) =>
Expand Down
99 changes: 61 additions & 38 deletions spec/03-types.md
Expand Up @@ -778,25 +778,22 @@ These notions are defined mutually recursively as follows.

## Relations between types

We define two relations between types.
We define the following relations between types.

|Name | Symbolically |Interpretation |
|-----------------|----------------|-------------------------------------------------|
|Equivalence |$T \equiv U$ |$T$ and $U$ are interchangeable in all contexts. |
|Conformance |$T <: U$ |Type $T$ conforms to type $U$. |
| Name | Symbolically | Interpretation |
|------------------|----------------|----------------------------------------------------|
| Equivalence | $T \equiv U$ | $T$ and $U$ are interchangeable in all contexts. |
| Conformance | $T <: U$ | Type $T$ conforms to ("is a subtype of") type $U$. |
| Weak Conformance | $T <:_w U$ | Augments conformance for primitive numeric types. |
| Compatibility | | Type $T$ conforms to type $U$ after conversions. |

### Equivalence

Equivalence $(\equiv)$ between types is the smallest congruence [^congruence] such that
the following holds:
Equivalence $(\equiv)$ between types is the smallest congruence [^congruence] such that the following holds:

- If $t$ is defined by a type alias `type $t$ = $T$`, then $t$ is
equivalent to $T$.
- If a path $p$ has a singleton type `$q$.type`, then
`$p$.type $\equiv q$.type`.
- If $O$ is defined by an object definition, and $p$ is a path
consisting only of package or object selectors and ending in $O$, then
`$O$.this.type $\equiv p$.type`.
- If $t$ is defined by a type alias `type $t$ = $T$`, then $t$ is equivalent to $T$.
- If a path $p$ has a singleton type `$q$.type`, then `$p$.type $\equiv q$.type`.
- If $O$ is defined by an object definition, and $p$ is a path consisting only of package or object selectors and ending in $O$, then `$O$.this.type $\equiv p$.type`.
- Two [compound types](#compound-types) are equivalent if the sequences
of their component are pairwise equivalent, and occur in the same order, and
their refinements are equivalent. Two refinements are equivalent if they
Expand Down Expand Up @@ -827,14 +824,11 @@ the following holds:

### Conformance

The conformance relation $(<:)$ is the smallest
transitive relation that satisfies the following conditions.
The conformance relation $(<:)$ is the smallest transitive relation that satisfies the following conditions.

- Conformance includes equivalence. If $T \equiv U$ then $T <: U$.
- For every value type $T$, `scala.Nothing <: $T$ <: scala.Any`.
- For every type constructor $T$ (with any number of type parameters),
`scala.Nothing <: $T$ <: scala.Any`.

- For every type constructor $T$ (with any number of type parameters), `scala.Nothing <: $T$ <: scala.Any`.
- For every class type $T$ such that `$T$ <: scala.AnyRef` one has `scala.Null <: $T$`.
- A type variable or abstract type $t$ conforms to its upper bound and
its lower bound conforms to $t$.
Expand Down Expand Up @@ -912,15 +906,12 @@ type $C'$, if one of the following holds.
type declaration `type t[$T_1$ , … , $T_n$] >: L <: U` if
$L <: t <: U$.

The $(<:)$ relation forms pre-order between types,
i.e. it is transitive and reflexive. _least upper bounds_ and
_greatest lower bounds_ of a set of types
are understood to be relative to that order.

###### Note
The least upper bound or greatest lower bound
of a set of types does not always exist. For instance, consider
the class definitions
#### Least upper bounds and greatest lower bounds
The $(<:)$ relation forms pre-order between types, i.e. it is transitive and reflexive.
This allows us to define _least upper bounds_ and _greatest lower bounds_ of a set of types in terms of that order.
The least upper bound or greatest lower bound of a set of types does not always exist.
For instance, consider the class definitions:

```scala
class A[+T] {}
Expand Down Expand Up @@ -949,11 +940,9 @@ free to pick any one of them.

### Weak Conformance

In some situations Scala uses a more general conformance relation. A
type $S$ _weakly conforms_
to a type $T$, written $S <:_w
T$, if $S <: T$ or both $S$ and $T$ are primitive number types
and $S$ precedes $T$ in the following ordering.
In some situations Scala uses a more general conformance relation.
A type $S$ _weakly conforms_ to a type $T$, written $S <:_w T$,
if $S <: T$ or both $S$ and $T$ are primitive number types and $S$ precedes $T$ in the following ordering.

```scala
Byte $<:_w$ Short
Expand All @@ -964,15 +953,49 @@ Long $<:_w$ Float
Float $<:_w$ Double
```

A _weak least upper bound_ is a least upper bound with respect to
weak conformance.
A _weak least upper bound_ is a least upper bound with respect to weak conformance.

### Compatibility
A type $T$ is _compatible_ to a type $U$ if $T$ (or its corresponding function type) [weakly conforms](#weak-conformance) to $U$
after applying [eta-expansion](06-expressions.html#eta-expansion). If $T$ is a method type, it's converted to the corresponding function type. If the types do not weakly conform, the following alternatives are checked in order:
- [view application](07-implicits.html#views): there's an implicit view from $T$ to $U$;
- dropping by-name modifiers: if $U$ is of the shape `$=> U'$` (and $T$ is not), `$T <:_w U'$`;
- SAM conversion: if $T$ corresponds to a function type, and $U$ declares a single abstract method whose type [corresponds](06-expressions.html#sam-conversion) to the function type $U'$, `$T <:_w U'$`.

<!--- TODO: include other implicit conversions in addition to view application?
trait Proc { def go(x: Any): Unit }
def foo(x: Any => Unit): Unit = ???
def foo(x: Proc): Unit = ???
foo((x: Any) => 1) // works when you drop either foo overload since value discarding is applied
-->

#### Examples

##### Function compatibility via SAM conversion

Given the definitions

```
def foo(x: Int => String): Unit
def foo(x: ToString): Unit
trait ToString { def convert(x: Int): String }
```

The application `foo((x: Int) => x.toString)` [resolves](06-expressions.html#overloading-resolution) to the first overload,
as it's more specific:
- `Int => String` is compatible to `ToString` -- when expecting a value of type `ToString`, you may pass a function literal from `Int` to `String`, as it will be SAM-converted to said function;
- `ToString` is not compatible to `Int => String` -- when expecting a function from `Int` to `String`, you may not pass a `ToString`.

## Volatile Types

Type volatility approximates the possibility that a type parameter or abstract
type instance
of a type does not have any non-null values. A value member of a volatile type
cannot appear in a [path](#paths).
Type volatility approximates the possibility that a type parameter or
abstract type instance of a type does not have any non-null values.
A value member of a volatile type cannot appear in a [path](#paths).

A type is _volatile_ if it falls into one of four categories:

Expand Down

0 comments on commit 5654ebd

Please sign in to comment.