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

Basic implementation of 42.type #45

Closed
wants to merge 3 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
11 changes: 3 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
12 changes: 10 additions & 2 deletions bincompat-forward.whitelist.conf
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ filter {
problemName=MissingClassProblem
},
{
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.scala$reflect$api$Trees$SingletonTypeTreeApi$$$outer"
problemName=MissingMethodProblem
},
{
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.isLiteral"
problemName=MissingMethodProblem
},
{
Expand Down Expand Up @@ -393,6 +397,10 @@ filter {
{
matchName="scala.reflect.runtime.Settings.ZirrefutableGeneratorPatterns"
problemName=MissingMethodProblem
}
},
{
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
problemName=MissingMethodProblem
}
]
}
9 changes: 5 additions & 4 deletions spec/03-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,13 @@ forms.

```ebnf
SimpleType ::= Path ‘.’ type
| Literal [‘.’ type]
```

A singleton type is of the form $p.$`type`, where $p$ is a
path pointing to a value expected to [conform](06-expressions.html#expression-typing)
to `scala.AnyRef`. The type denotes the set of values
consisting of `null` and the value denoted by $p$.
A singleton type is of the form $p.$`type`, where $p$ is a path,
or $42$, with `.type` being optional for literals.
The type denotes the set of values consisting of `null` and the
value denoted by $p$.

A _stable type_ is either a singleton type or a type which is
declared to be a subtype of trait `scala.Singleton`.
Expand Down
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 @@ -675,11 +675,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 @@ -862,7 +862,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 @@ -1108,6 +1114,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
4 changes: 2 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,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 Down Expand Up @@ -876,7 +876,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
18 changes: 11 additions & 7 deletions src/compiler/scala/tools/nsc/typechecker/Typers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,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 @@ -990,6 +990,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 @@ -1090,7 +1091,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 @@ -3464,6 +3465,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 @@ -3527,6 +3529,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 @@ -5093,11 +5096,12 @@ 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 {
refTyped.tpe.resultType.asDeclaredSingleton.getOrElse(refTyped.tpe.resultType)
}
if (!refTyped.isErrorTyped)
tree setType refTyped.tpe.resultType

Expand Down
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
}

/** 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
21 changes: 17 additions & 4 deletions src/reflect/scala/reflect/internal/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ trait Types

/** The base class for all types */
abstract class Type extends TypeApiImpl with Annotatable[Type] {
val isDeclaredSingleton: Boolean = false
def asDeclaredSingleton: Option[DeclaredSingletonType] = None

/** Types for which asSeenFrom always is the identity, no matter what
* prefix or owner.
*/
Expand Down Expand Up @@ -1811,15 +1814,25 @@ trait Types
class PackageClassInfoType(decls: Scope, clazz: Symbol)
extends ClassInfoType(List(), decls, clazz)

final case class DeclaredSingletonType(value: Constant) extends SingletonType with SingletonTypeApi {
override val isDeclaredSingleton = true
override def asDeclaredSingleton = Some(this)
override def underlying: Type = value.tpe
override def isTrivial: Boolean = true
override def deconst = underlying
override def safeToString: String = value.escapedStringValue + ".type"
override def kind = "DeclaredSingletonType"
}

/** A class representing a constant type.
*/
abstract case class ConstantType(value: Constant) extends SingletonType with ConstantTypeApi {
override def asDeclaredSingleton = Some(DeclaredSingletonType(value))
override def underlying: Type = value.tpe
assert(underlying.typeSymbol != UnitClass)
override def isTrivial: Boolean = true
override def deconst: Type = underlying.deconst
override def safeToString: String =
underlying.toString + "(" + value.escapedStringValue + ")"
override def deconst: Type = underlying
override def safeToString: String = value.escapedStringValue + ".type"
override def kind = "ConstantType"
}

Expand Down Expand Up @@ -2421,7 +2434,7 @@ trait Types
if (isTrivial || phase.erasedTypes) resultType
else if (/*isDependentMethodType &&*/ sameLength(actuals, params)) {
val idm = new InstantiateDependentMap(params, actuals)
val res = idm(resultType)
val res = idm(resultType).deconst
existentialAbstraction(idm.existentialsNeeded, res)
}
else existentialAbstraction(params, resultType)
Expand Down
1 change: 1 addition & 0 deletions src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.baseClassesCycleMonitor
this.RefinedType
this.ClassInfoType
this.DeclaredSingletonType
this.ConstantType
this.TypeRef
this.MethodType
Expand Down
2 changes: 1 addition & 1 deletion test/files/jvm/interpreter.check
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ four: anotherint = 4

scala> val bogus: anotherint = "hello"
<console>:8: error: type mismatch;
found : String("hello")
found : "hello".type (with underlying type String)
required: anotherint
(which expands to) Int
val bogus: anotherint = "hello"
Expand Down
34 changes: 1 addition & 33 deletions test/files/neg/any-vs-anyref.check
Original file line number Diff line number Diff line change
@@ -1,35 +1,3 @@
any-vs-anyref.scala:6: error: type mismatch;
found : a.type (with underlying type A)
required: AnyRef
Note that A is bounded only by Equals, which means AnyRef is not a known parent.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
def foo1[A <: Product](a: A) = { type X = a.type }
^
any-vs-anyref.scala:7: error: type mismatch;
found : a.type (with underlying type A)
required: AnyRef
Note that A is bounded only by Product, Quux, which means AnyRef is not a known parent.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
def foo2[A <: Product with Quux](a: A) = { type X = a.type }
^
any-vs-anyref.scala:8: error: type mismatch;
found : a.type (with underlying type Product)
required: AnyRef
Note that Product extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
def foo3(a: Product) = { type X = a.type }
^
any-vs-anyref.scala:9: error: type mismatch;
found : Product with Quux
required: AnyRef
Note that the parents of this type (Product, Quux) extend Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
def foo4(a: Product with Quux) = { type X = a.type }
^
any-vs-anyref.scala:10: error: value eq is not a member of Quux with Product
Note that the parents of this type (Quux, Product) extend Any, not AnyRef.
Such types can participate in value classes, but instances
Expand Down Expand Up @@ -77,4 +45,4 @@ any-vs-anyref.scala:27: error: type mismatch;
required: Quux{def g(x: Int): Int}
f(new Quux { def g(x: String) = x })
^
11 errors found
7 errors found
Loading