Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

42.type #18

Closed
wants to merge 16 commits into from
Closed
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
15 changes: 7 additions & 8 deletions bincompat-backward.whitelist.conf
Original file line number Diff line number Diff line change
Expand Up @@ -134,22 +134,17 @@ filter {
problemName=MissingMethodProblem
},
{
matchName="scala.reflect.api.Mirror.symbolOf"
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.isLiteral"
problemName=MissingMethodProblem
},
{
matchName="scala.reflect.api.Mirror.typeOf"
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.scala$reflect$api$Trees$SingletonTypeTreeApi$$$outer"
problemName=MissingMethodProblem
},
{
matchName="scala.reflect.api.Mirror.weakTypeOf"
matchName="scala.reflect.api.Mirror.symbolOf"
problemName=MissingMethodProblem
},
// see SI-8388
{
matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticIdentExtractor"
problemName=MissingClassProblem
},
{
matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticIdent"
problemName=MissingMethodProblem
Expand Down Expand Up @@ -194,6 +189,10 @@ filter {
{
matchName="scala.collection.immutable.Stream.filteredTail"
problemName=MissingMethodProblem
},
{
matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticIdentExtractor"
problemName=MissingClassProblem
}
]
}
12 changes: 12 additions & 0 deletions bincompat-forward.whitelist.conf
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,18 @@ filter {
{
matchName="scala.reflect.io.AbstractFile.filterImpl"
problemName=MissingMethodProblem
},
{
matchName="scala.Predef.inhabitant"
problemName=MissingMethodProblem
},
{
matchName="scala.SingleInhabitant$"
problemName=MissingClassProblem
},
{
matchName="scala.SingleInhabitant"
problemName=MissingClassProblem
}
]
}
3 changes: 2 additions & 1 deletion src/compiler/scala/reflect/reify/codegen/GenTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ trait GenTypes {
reifyBuildCall(nme.SuperType, thistpe, supertpe)
case tpe @ SingleType(pre, sym) =>
reifyBuildCall(nme.SingleType, pre, sym)
case tpe @ ConstantType(value) =>
// TODO (folone): ConstantType folding?
case tpe @ ConstantType(value) if !tpe.isDeclaredSingleton =>
mirrorBuildCall(nme.ConstantType, reifyProduct(value))
case tpe @ TypeRef(pre, sym, args) =>
reifyBuildCall(nme.TypeRef, pre, sym, args)
Expand Down
22 changes: 18 additions & 4 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,11 @@ self =>

def isExprIntro: Boolean = isExprIntroToken(in.token)

def isTypeIntroToken(token: Token): Boolean = token match {
def isTypeIntroToken(token: Token): Boolean = isLiteralToken(token) || (token match {
case IDENTIFIER | BACKQUOTED_IDENT | THIS |
SUPER | USCORE | LPAREN | AT => true
SUPER | USCORE | LPAREN | AT | NULL => true
case _ => false
}
})

def isStatSeqEnd = in.token == RBRACE || in.token == EOF

Expand Down Expand Up @@ -861,7 +861,13 @@ self =>
in.nextToken()
if (in.token == RPAREN) {
in.nextToken()
atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) }
if (in.token == DOT && lookingAhead { in.token == TYPE }) {
accept(DOT)
accept(TYPE)
atPos(start)(new SingletonTypeTree(Literal(Constant(()))) { override val isLiteral = true })
} else {
atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) }
}
}
else {
val ts = functionTypes()
Expand Down Expand Up @@ -1090,6 +1096,14 @@ self =>
if (in.token == DOT) t = selectors(t, typeOK, in.skipToken())
} else {
val tok = in.token
if (tok != BACKQUOTED_IDENT && tok != IDENTIFIER) {
val lit = literal(false)
if (in.token == DOT && lookingAhead { in.token == TYPE }) {
accept(DOT)
accept(TYPE)
}
return atPos(start)(new SingletonTypeTree(lit) { override val isLiteral = true })
}
val name = ident()
t = atPos(start) {
if (tok == BACKQUOTED_IDENT) Ident(name) updateAttachment BackquotedIdentifierAttachment
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
// methods with constant result type get literals as their body
// all methods except the primary constructor go into template
stat.symbol.tpe match {
// TODO (folone): inlining of defs with literal-based singleton type results?
case MethodType(List(), tp @ ConstantType(c)) =>
defBuf += deriveDefDef(stat)(Literal(c) setPos _.pos setType tp)
case _ =>
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,8 @@ abstract class Erasure extends AddInterfaces
} else bridgingCall
}
val rhs = member.tpe match {
case MethodType(Nil, ConstantType(c)) => Literal(c)
// TODO (folone): inlining of defs with literal-based singleton type results?
case MethodType(Nil, tp @ ConstantType(c)) if !tp.isDeclaredSingleton => Literal(c)
case _ =>
val sel: Tree = Select(This(root), member)
val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
val alternativesSupported = true
val canJump = true

// TODO (folone): ConstantType folding?
// Constant folding sets the type of a constant tree to `ConstantType(Constant(folded))`
// The tree itself can be a literal, an ident, a selection, ...
object SwitchablePattern { def unapply(pat: Tree): Option[Tree] = pat.tpe match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import java.lang.ArithmeticException
* @author Martin Odersky
* @version 1.0
*/
// TODO (folone): ConstantType folding?
abstract class ConstantFolder {

val global: Global
Expand All @@ -30,7 +31,7 @@ abstract class ConstantFolder {
* the conversion.
*/
def apply(tree: Tree, pt: Type): Tree = fold(apply(tree), tree.tpe match {
case ConstantType(x) => x convertTo pt
case t @ ConstantType(x) if !t.isDeclaredSingleton => x convertTo pt
case _ => null
})

Expand Down
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/typechecker/Infer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ trait Infer extends Checkable {
else Some(
if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass)
else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass)
else if (targ.isDeclaredSingleton) targ
// this infers Foo.type instead of "object Foo" (see also widenIfNecessary)
else if (targ.typeSymbol.isModuleClass || tvar.constr.avoidWiden) targ
else targ.widen
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ trait Namers extends MethodSynthesis {
var _lockedCount = 0
def lockedCount = this._lockedCount

private var inferDependentTypes = false

/** Replaces any Idents for which cond is true with fresh TypeTrees().
* Does the same for any trees containing EmptyTrees.
*/
Expand Down Expand Up @@ -838,7 +840,7 @@ trait Namers extends MethodSynthesis {
* value should not be widened, so it has a use even in situations
* whether it is otherwise redundant (such as in a singleton.)
*/
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type = {
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type, isLiteral: Boolean): Type = {
val getter =
if (sym.isValue && sym.owner.isClass && sym.isPrivate)
sym.getter(sym.owner)
Expand All @@ -863,7 +865,7 @@ trait Namers extends MethodSynthesis {
)
dropIllegalStarTypes(
if (shouldWiden) tpe.widen
else if (sym.isFinal) tpe // "final val" allowed to retain constant type
else if (sym.isFinal || (isLiteral && inferDependentTypes)) tpe // "final val" allowed to retain constant type
else tpe.deconst
)
}
Expand All @@ -876,7 +878,7 @@ trait Namers extends MethodSynthesis {
case _ => defnTyper.computeType(tree.rhs, pt)
}

val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt, tree.rhs.isInstanceOf[Literal])
tree.tpt defineType defnTpe setPos tree.pos.focus
tree.tpt.tpe
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ trait TypeDiagnostics {
&& !targets(m)
&& !(m.name == nme.WILDCARD) // e.g. val _ = foo
&& !ignoreNames(m.name.toTermName) // serialization methods
// TODO (folone): inlining of defs with literal-based singleton type results?
&& !isConstantType(m.info.resultType) // subject to constant inlining
&& !treeTypes.exists(_ contains m) // e.g. val a = new Foo ; new a.Bar
)
Expand Down
19 changes: 12 additions & 7 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
* given mode `mode` and given prototype `pt`:
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode or dealing with a singleton type)
* (1) Resolve overloading, unless mode contains FUNmode
* (2) Apply parameterless functions
* (3) Apply polymorphic types to fresh instances of their type parameters and
Expand Down Expand Up @@ -996,6 +996,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (mode.inPatternMode && isPopulatedPattern)
return tree

// TODO (folone): ConstantType folding?
val tree1 = constfold(tree, pt) // (10) (11)
if (tree1.tpe <:< pt)
return adapt(tree1, mode, pt, original)
Expand Down Expand Up @@ -1096,7 +1097,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
} else tree.tpe match {
case atp @ AnnotatedType(_, _) if canAdaptAnnotations(tree, this, mode, pt) => // (-1)
adaptAnnotations(tree, this, mode, pt)
case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && canAdaptConstantTypeToLiteral => // (0)
case ct @ ConstantType(value) if mode.inNone(TYPEmode | FUNmode) && (ct <:< pt) && canAdaptConstantTypeToLiteral && !ct.isDeclaredSingleton => // (0)
adaptConstant(value)
case OverloadedType(pre, alts) if !mode.inFunMode => // (1)
inferExprAlternative(tree, pt)
Expand Down Expand Up @@ -3478,6 +3479,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ErroneousAnnotation
}

// TODO (folone): ConstantType folding?
/* Calling constfold right here is necessary because some trees (negated
* floats and literals in particular) are not yet folded.
*/
Expand Down Expand Up @@ -3541,6 +3543,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case Typed(t, _) =>
tree2ConstArg(t, pt)

// TODO (folone): ConstantType folding?
case tree =>
tryConst(tree, pt)
}
Expand Down Expand Up @@ -5107,11 +5110,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}

def typedSingletonTypeTree(tree: SingletonTypeTree) = {
val refTyped =
context.withImplicitsDisabled {
typed(tree.ref, MonoQualifierModes | mode.onlyTypePat, AnyRefTpe)
}

val refTyped = context.withImplicitsDisabled {
typed(tree.ref, MonoQualifierModes | mode.onlyTypePat, AnyClass.tpe)
}
tree setType {
if (tree.isLiteral) refTyped.tpe.resultType.asDeclaredSingleton
else refTyped.tpe.resultType
}
if (!refTyped.isErrorTyped)
tree setType refTyped.tpe.resultType

Expand Down
5 changes: 3 additions & 2 deletions src/compiler/scala/tools/reflect/FastTrack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class FastTrack[MacrosAndAnalyzer <: Macros with Analyzer](val macros: MacrosAnd

private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } =
new { val c: c0.type = c0 } with Taggers
private implicit def context2macroimplementations(c0: MacroContext): FormatInterpolator { val c: c0.type } =
new { val c: c0.type = c0 } with FormatInterpolator
private implicit def context2macroimplementations(c0: MacroContext): FormatInterpolator with SingleInhabitantMacro { val c: c0.type } =
new { val c: c0.type = c0 } with FormatInterpolator with SingleInhabitantMacro
private implicit def context2quasiquote(c0: MacroContext): QuasiquoteImpls { val c: c0.type } =
new { val c: c0.type = c0 } with QuasiquoteImpls
private def makeBlackbox(sym: Symbol)(pf: PartialFunction[Applied, MacroContext => Tree]) =
Expand All @@ -51,6 +51,7 @@ class FastTrack[MacrosAndAnalyzer <: Macros with Analyzer](val macros: MacrosAnd
makeBlackbox( materializeWeakTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = false) },
makeBlackbox( materializeTypeTag) { case Applied(_, ttag :: Nil, (u :: _) :: _) => _.materializeTypeTag(u, EmptyTree, ttag.tpe, concrete = true) },
makeBlackbox( ApiUniverseReify) { case Applied(_, ttag :: Nil, (expr :: _) :: _) => c => c.materializeExpr(c.prefix.tree, EmptyTree, expr) },
makeBlackbox( SingleInhabitant_witness) { case Applied(_, ttag :: Nil, _) => _.materialize(ttag.tpe) },
makeBlackbox( StringContext_f) { case _ => _.interpolate },
makeBlackbox(ReflectRuntimeCurrentMirror) { case _ => c => currentMirror(c).tree },
makeWhitebox( QuasiquoteClass_api_apply) { case _ => _.expandQuasiquote },
Expand Down
26 changes: 26 additions & 0 deletions src/compiler/scala/tools/reflect/SingleInhabitantMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package scala.tools.reflect

import scala.reflect.macros.runtime.Context


trait SingleInhabitantMacro { self: FormatInterpolator =>
val c: Context

import c.universe._

def materialize(tpe: Type): Tree = {
val value = tpe match {
case ConstantType(const) => Literal(const)
case SingleType(pre, sym) => Select(TypeTree(pre), sym)
case _ =>
c.abort(c.enclosingPosition, tpe + " is not a singleton type!")
}
Apply(
TypeApply(
Select(reify(SingleInhabitant).tree, newTermName("apply")),
TypeTree(tpe) :: Nil
),
value :: Nil
)
}
}
2 changes: 2 additions & 0 deletions src/library/scala/Predef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef {
// @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
def optManifest[T](implicit m: OptManifest[T]) = m

def inhabitant[A](implicit h: SingleInhabitant[A]) = h.a

// Minor variations on identity functions
def identity[A](x: A): A = x // @see `conforms` for the implicit version
@inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero`
Expand Down
18 changes: 18 additions & 0 deletions src/library/scala/SingleInhabitant.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */

package scala

import scala.language.experimental.macros


case class SingleInhabitant[A](a: A)

object SingleInhabitant {
implicit def witness[A]: SingleInhabitant[A] = macro ???
}
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/api/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,7 @@ trait Trees { self: Universe =>
trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree =>
/** The underlying reference. */
def ref: Tree
def isLiteral = false // TODO: какое-то стремное имя как на мой вкус
}

/** Type selection <qualifier> # <name>, eliminated by RefCheck
Expand Down
4 changes: 2 additions & 2 deletions src/reflect/scala/reflect/api/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,8 @@ trait Types {
*/
def supertpe: Type
}
/** The `ConstantType` type is not directly written in user programs, but arises as the type of a constant.
* The REPL expresses constant types like `Int(11)`. Here are some constants with their types:
/** The `ConstantType` type is not directly written in user programs (now it is), but arises as the type of a constant.
* The REPL expresses constant types like `11.type`. Here are some constants with their types:
* {{{
* 1 ConstantType(Constant(1))
* "abc" ConstantType(Constant("abc"))
Expand Down
4 changes: 4 additions & 0 deletions src/reflect/scala/reflect/internal/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ trait Definitions extends api.StandardDefinitions {

lazy val StringContextClass = requiredClass[scala.StringContext]

lazy val SingleInhabitantModule = requiredModule[scala.SingleInhabitant.type]

// SI-8392 a reflection universe on classpath may not have
// quasiquotes, if e.g. crosstyping with -Xsource on
lazy val QuasiquoteClass = if (ApiUniverseClass != NoSymbol) getMemberIfDefined(ApiUniverseClass, tpnme.Quasiquote) else NoSymbol
Expand Down Expand Up @@ -1411,6 +1413,8 @@ trait Definitions extends api.StandardDefinitions {

lazy val StringContext_f = getMemberMethod(StringContextClass, nme.f)

lazy val SingleInhabitant_witness = getMemberMethod(SingleInhabitantModule, nme.witness)

lazy val ArrowAssocClass = getMemberClass(PredefModule, TypeName("ArrowAssoc")) // SI-5731
def isArrowAssoc(sym: Symbol) = sym.owner == ArrowAssocClass

Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/internal/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ trait StdNames {
val values : NameType = "values"
val wait_ : NameType = "wait"
val withFilter: NameType = "withFilter"
val witness: NameType = "witness"
val zero: NameType = "zero"

// quasiquote interpolators:
Expand Down
Loading