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

Unify treatment of built-in functions and SAMs #4971

Merged
merged 36 commits into from Mar 31, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b86021f
sbt build targets build/
adriaanm Mar 18, 2016
4356ac7
TypeHistory's toString time travels consistently
adriaanm Feb 18, 2016
52496ba
Remove dead code now that `genBCodeActive` is always true.
adriaanm Feb 8, 2016
828105f
Refactor. Extract mkLiteralUnit and mkUnitBlock
adriaanm Mar 24, 2016
66b0389
Spec updates for Sammy.
adriaanm Jan 21, 2016
4f4fb45
SI-9415 Turn on SAM by default
retronym Sep 24, 2015
236d0e0
Refactor typedFunction, rework synthesizeSAMFunction for sammy
adriaanm Jan 20, 2016
0d89ab1
SI-9449 sam expansion for explicitly eta-expanded method
adriaanm Feb 4, 2016
ad90614
Refactoring. Sweep Sammy's backyard.
adriaanm Feb 5, 2016
1acfc70
Set the scene for Sammy.
adriaanm Mar 16, 2016
651d67c
Review feedback from Lukas
adriaanm Mar 16, 2016
8433b6f
Treat `Function` literals uniformly, expecting SAM or FunctionN.
adriaanm Feb 9, 2016
8a7919b
Refactoring. Decakify TypeAdaptingTransformer
adriaanm Mar 17, 2016
5f71e2e
For backwards compat, sammy comes last
adriaanm Mar 17, 2016
a2795ba
Refactoring. Simplify inferImplicit's boolean levers
adriaanm Mar 18, 2016
040c043
More fixes based on feedback by Lukas
adriaanm Mar 18, 2016
f922f36
Additional SAM restrictions identified by Jason
adriaanm Mar 17, 2016
2aa8eba
Test bytecode emitted for indy sammy
adriaanm Mar 21, 2016
49d946d
Refactor flag juggling. Review feedback from Jason.
adriaanm Mar 22, 2016
b0b0aba
Jason's review feedback (ThisReferringMethodTraverser)
adriaanm Mar 22, 2016
391e284
Don't adapt erroneous tree to SAM type.
adriaanm Mar 22, 2016
878e20a
Track Function's SAM symbol & target type using an attachment
adriaanm Mar 22, 2016
608ac2c
Soften sam restrictions
adriaanm Mar 23, 2016
aa972dc
SAM conversion precedes implicit view application (as in dotty).
adriaanm Mar 24, 2016
925b394
Refactor: simplify fallbackAfterVanillaAdapt.
adriaanm Mar 24, 2016
a17d247
SAM conversion can be disabled using `-Xsource:2.11`
adriaanm Mar 26, 2016
3ae3903
Target FunctionN, not scala/runtime/java8/JFunction.
adriaanm Mar 26, 2016
0a3362b
Specialization precludes use of LambdaMetaFactory for SAM
adriaanm Mar 29, 2016
63f0175
Better detection of types LMF cannot instantiate.
adriaanm Mar 29, 2016
62d97d7
LMF cannot run trait's "initializer" (constructor)
adriaanm Mar 30, 2016
3904c32
LMF cannot instantiate SAM of trait with non-trait superclass
adriaanm Mar 30, 2016
aec2b94
Keep SAM body in anonfun method in enclosing class
retronym Mar 30, 2016
7025be9
Bring back AbstractFunction parent
adriaanm Mar 30, 2016
8e32d00
Keep Function when CBN arg thunk targets a SAM
adriaanm Mar 31, 2016
5d7d644
typedFunction undoes eta-expansion regardless of expected type
adriaanm Mar 31, 2016
5e5ab18
Clarify how/when typedFunction unrolls eta-expansion
adriaanm Mar 31, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -715,8 +715,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 @@ -775,7 +775,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