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

Commit 83d0b6a

Browse files
committed
Basic implementation of 42.type:
- Implements mandatory `.type` for identifiers - Implements optional `.type` for literals - Fixes a few problems with it, updates .check files
1 parent d76ccf3 commit 83d0b6a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+290
-200
lines changed

bincompat-backward.whitelist.conf

+3-8
Original file line numberDiff line numberDiff line change
@@ -134,22 +134,17 @@ filter {
134134
problemName=MissingMethodProblem
135135
},
136136
{
137-
matchName="scala.reflect.api.Mirror.symbolOf"
137+
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.isLiteral"
138138
problemName=MissingMethodProblem
139139
},
140140
{
141-
matchName="scala.reflect.api.Mirror.typeOf"
141+
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.scala$reflect$api$Trees$SingletonTypeTreeApi$$$outer"
142142
problemName=MissingMethodProblem
143143
},
144144
{
145-
matchName="scala.reflect.api.Mirror.weakTypeOf"
145+
matchName="scala.reflect.api.Mirror.symbolOf"
146146
problemName=MissingMethodProblem
147147
},
148-
// see SI-8388
149-
{
150-
matchName="scala.reflect.api.Internals$ReificationSupportApi$SyntacticIdentExtractor"
151-
problemName=MissingClassProblem
152-
},
153148
{
154149
matchName="scala.reflect.api.Internals#ReificationSupportApi.SyntacticIdent"
155150
problemName=MissingMethodProblem

bincompat-forward.whitelist.conf

+10-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,11 @@ filter {
228228
problemName=MissingClassProblem
229229
},
230230
{
231-
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
231+
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.scala$reflect$api$Trees$SingletonTypeTreeApi$$$outer"
232+
problemName=MissingMethodProblem
233+
},
234+
{
235+
matchName="scala.reflect.api.Trees#SingletonTypeTreeApi.isLiteral"
232236
problemName=MissingMethodProblem
233237
},
234238
{
@@ -393,6 +397,10 @@ filter {
393397
{
394398
matchName="scala.reflect.runtime.Settings.ZirrefutableGeneratorPatterns"
395399
problemName=MissingMethodProblem
396-
}
400+
},
401+
{
402+
matchName="scala.reflect.runtime.JavaMirrors#JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$followStatic"
403+
problemName=MissingMethodProblem
404+
}
397405
]
398406
}

src/compiler/scala/reflect/reify/codegen/GenTypes.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ trait GenTypes {
5252
reifyBuildCall(nme.SuperType, thistpe, supertpe)
5353
case tpe @ SingleType(pre, sym) =>
5454
reifyBuildCall(nme.SingleType, pre, sym)
55-
case tpe @ ConstantType(value) =>
55+
// TODO (folone): ConstantType folding?
56+
case tpe @ ConstantType(value) if !tpe.isDeclaredSingleton =>
5657
mirrorBuildCall(nme.ConstantType, reifyProduct(value))
5758
case tpe @ TypeRef(pre, sym, args) =>
5859
reifyBuildCall(nme.TypeRef, pre, sym, args)

src/compiler/scala/tools/nsc/ast/parser/Parsers.scala

+18-4
Original file line numberDiff line numberDiff line change
@@ -674,11 +674,11 @@ self =>
674674

675675
def isExprIntro: Boolean = isExprIntroToken(in.token)
676676

677-
def isTypeIntroToken(token: Token): Boolean = token match {
677+
def isTypeIntroToken(token: Token): Boolean = isLiteralToken(token) || (token match {
678678
case IDENTIFIER | BACKQUOTED_IDENT | THIS |
679-
SUPER | USCORE | LPAREN | AT => true
679+
SUPER | USCORE | LPAREN | AT | NULL => true
680680
case _ => false
681-
}
681+
})
682682

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

@@ -861,7 +861,13 @@ self =>
861861
in.nextToken()
862862
if (in.token == RPAREN) {
863863
in.nextToken()
864-
atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) }
864+
if (in.token == DOT && lookingAhead { in.token == TYPE }) {
865+
accept(DOT)
866+
accept(TYPE)
867+
atPos(start)(new SingletonTypeTree(Literal(Constant(()))) { override val isLiteral = true })
868+
} else {
869+
atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) }
870+
}
865871
}
866872
else {
867873
val ts = functionTypes()
@@ -1090,6 +1096,14 @@ self =>
10901096
if (in.token == DOT) t = selectors(t, typeOK, in.skipToken())
10911097
} else {
10921098
val tok = in.token
1099+
if (tok != BACKQUOTED_IDENT && tok != IDENTIFIER) {
1100+
val lit = literal(false)
1101+
if (in.token == DOT && lookingAhead { in.token == TYPE }) {
1102+
accept(DOT)
1103+
accept(TYPE)
1104+
}
1105+
return atPos(start)(new SingletonTypeTree(lit) { override val isLiteral = true })
1106+
}
10931107
val name = ident()
10941108
t = atPos(start) {
10951109
if (tok == BACKQUOTED_IDENT) Ident(name) updateAttachment BackquotedIdentifierAttachment

src/compiler/scala/tools/nsc/transform/Constructors.scala

+1
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
640640
// methods with constant result type get literals as their body
641641
// all methods except the primary constructor go into template
642642
stat.symbol.tpe match {
643+
// TODO (folone): inlining of defs with literal-based singleton type results?
643644
case MethodType(List(), tp @ ConstantType(c)) =>
644645
defBuf += deriveDefDef(stat)(Literal(c) setPos _.pos setType tp)
645646
case _ =>

src/compiler/scala/tools/nsc/transform/Erasure.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ abstract class Erasure extends AddInterfaces
535535
} else bridgingCall
536536
}
537537
val rhs = member.tpe match {
538-
case MethodType(Nil, ConstantType(c)) => Literal(c)
538+
// TODO (folone): inlining of defs with literal-based singleton type results?
539+
case MethodType(Nil, tp @ ConstantType(c)) if !tp.isDeclaredSingleton => Literal(c)
539540
case _ =>
540541
val sel: Tree = Select(This(root), member)
541542
val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident))

src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala

+1
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
496496
val alternativesSupported = true
497497
val canJump = true
498498

499+
// TODO (folone): ConstantType folding?
499500
// Constant folding sets the type of a constant tree to `ConstantType(Constant(folded))`
500501
// The tree itself can be a literal, an ident, a selection, ...
501502
object SwitchablePattern { def unapply(pat: Tree): Option[Tree] = pat.tpe match {

src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import java.lang.ArithmeticException
1414
* @author Martin Odersky
1515
* @version 1.0
1616
*/
17+
// TODO (folone): ConstantType folding?
1718
abstract class ConstantFolder {
1819

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

src/compiler/scala/tools/nsc/typechecker/Infer.scala

+1
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ trait Infer extends Checkable {
477477
else Some(
478478
if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass)
479479
else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass)
480+
else if (targ.isDeclaredSingleton) targ
480481
// this infers Foo.type instead of "object Foo" (see also widenIfNecessary)
481482
else if (targ.typeSymbol.isModuleClass || tvar.constr.avoidWiden) targ
482483
else targ.widen

src/compiler/scala/tools/nsc/typechecker/Namers.scala

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ trait Namers extends MethodSynthesis {
2525
var _lockedCount = 0
2626
def lockedCount = this._lockedCount
2727

28+
private var inferDependentTypes = false
29+
2830
/** Replaces any Idents for which cond is true with fresh TypeTrees().
2931
* Does the same for any trees containing EmptyTrees.
3032
*/
@@ -838,7 +840,7 @@ trait Namers extends MethodSynthesis {
838840
* value should not be widened, so it has a use even in situations
839841
* whether it is otherwise redundant (such as in a singleton.)
840842
*/
841-
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type): Type = {
843+
private def widenIfNecessary(sym: Symbol, tpe: Type, pt: Type, isLiteral: Boolean): Type = {
842844
val getter =
843845
if (sym.isValue && sym.owner.isClass && sym.isPrivate)
844846
sym.getter(sym.owner)
@@ -863,7 +865,7 @@ trait Namers extends MethodSynthesis {
863865
)
864866
dropIllegalStarTypes(
865867
if (shouldWiden) tpe.widen
866-
else if (sym.isFinal) tpe // "final val" allowed to retain constant type
868+
else if (sym.isFinal || (isLiteral && inferDependentTypes)) tpe // "final val" allowed to retain constant type
867869
else tpe.deconst
868870
)
869871
}
@@ -876,7 +878,7 @@ trait Namers extends MethodSynthesis {
876878
case _ => defnTyper.computeType(tree.rhs, pt)
877879
}
878880

879-
val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt)
881+
val defnTpe = widenIfNecessary(tree.symbol, rhsTpe, pt, tree.rhs.isInstanceOf[Literal])
880882
tree.tpt defineType defnTpe setPos tree.pos.focus
881883
tree.tpt.tpe
882884
}

src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala

+1
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ trait TypeDiagnostics {
504504
&& !targets(m)
505505
&& !(m.name == nme.WILDCARD) // e.g. val _ = foo
506506
&& !ignoreNames(m.name.toTermName) // serialization methods
507+
// TODO (folone): inlining of defs with literal-based singleton type results?
507508
&& !isConstantType(m.info.resultType) // subject to constant inlining
508509
&& !treeTypes.exists(_ contains m) // e.g. val a = new Foo ; new a.Bar
509510
)

src/compiler/scala/tools/nsc/typechecker/Typers.scala

+12-7
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
744744
/** Perform the following adaptations of expression, pattern or type `tree` wrt to
745745
* given mode `mode` and given prototype `pt`:
746746
* (-1) For expressions with annotated types, let AnnotationCheckers decide what to do
747-
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode)
747+
* (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode or dealing with a singleton type)
748748
* (1) Resolve overloading, unless mode contains FUNmode
749749
* (2) Apply parameterless functions
750750
* (3) Apply polymorphic types to fresh instances of their type parameters and
@@ -996,6 +996,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
996996
if (mode.inPatternMode && isPopulatedPattern)
997997
return tree
998998

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

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

3546+
// TODO (folone): ConstantType folding?
35443547
case tree =>
35453548
tryConst(tree, pt)
35463549
}
@@ -5107,11 +5110,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
51075110
}
51085111

51095112
def typedSingletonTypeTree(tree: SingletonTypeTree) = {
5110-
val refTyped =
5111-
context.withImplicitsDisabled {
5112-
typed(tree.ref, MonoQualifierModes | mode.onlyTypePat, AnyRefTpe)
5113-
}
5114-
5113+
val refTyped = context.withImplicitsDisabled {
5114+
typed(tree.ref, MonoQualifierModes | mode.onlyTypePat, AnyClass.tpe)
5115+
}
5116+
tree setType {
5117+
if (tree.isLiteral) refTyped.tpe.resultType.asDeclaredSingleton
5118+
else refTyped.tpe.resultType
5119+
}
51155120
if (!refTyped.isErrorTyped)
51165121
tree setType refTyped.tpe.resultType
51175122

src/reflect/scala/reflect/api/Trees.scala

+1
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,7 @@ trait Trees { self: Universe =>
18721872
trait SingletonTypeTreeApi extends TypTreeApi { this: SingletonTypeTree =>
18731873
/** The underlying reference. */
18741874
def ref: Tree
1875+
def isLiteral = false
18751876
}
18761877

18771878
/** Type selection <qualifier> # <name>, eliminated by RefCheck

src/reflect/scala/reflect/api/Types.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,8 @@ trait Types {
528528
*/
529529
def supertpe: Type
530530
}
531-
/** The `ConstantType` type is not directly written in user programs, but arises as the type of a constant.
532-
* The REPL expresses constant types like `Int(11)`. Here are some constants with their types:
531+
/** The `ConstantType` type is not directly written in user programs (now it is), but arises as the type of a constant.
532+
* The REPL expresses constant types like `11.type`. Here are some constants with their types:
533533
* {{{
534534
* 1 ConstantType(Constant(1))
535535
* "abc" ConstantType(Constant("abc"))

src/reflect/scala/reflect/internal/Types.scala

+11-4
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ trait Types
258258

259259
/** The base class for all types */
260260
abstract class Type extends TypeApiImpl with Annotatable[Type] {
261+
var isDeclaredSingleton: Boolean = false
262+
def asDeclaredSingleton: this.type = {
263+
isDeclaredSingleton = true
264+
this
265+
}
266+
261267
/** Types for which asSeenFrom always is the identity, no matter what
262268
* prefix or owner.
263269
*/
@@ -1817,9 +1823,10 @@ trait Types
18171823
override def underlying: Type = value.tpe
18181824
assert(underlying.typeSymbol != UnitClass)
18191825
override def isTrivial: Boolean = true
1820-
override def deconst: Type = underlying.deconst
1821-
override def safeToString: String =
1822-
underlying.toString + "(" + value.escapedStringValue + ")"
1826+
override def deconst: Type =
1827+
if (isDeclaredSingleton) this
1828+
else underlying
1829+
override def safeToString: String = value.escapedStringValue + ".type"
18231830
override def kind = "ConstantType"
18241831
}
18251832

@@ -2421,7 +2428,7 @@ trait Types
24212428
if (isTrivial || phase.erasedTypes) resultType
24222429
else if (/*isDependentMethodType &&*/ sameLength(actuals, params)) {
24232430
val idm = new InstantiateDependentMap(params, actuals)
2424-
val res = idm(resultType)
2431+
val res = idm(resultType).deconst
24252432
existentialAbstraction(idm.existentialsNeeded, res)
24262433
}
24272434
else existentialAbstraction(params, resultType)

test/files/jvm/interpreter.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ four: anotherint = 4
3333

3434
scala> val bogus: anotherint = "hello"
3535
<console>:8: error: type mismatch;
36-
found : String("hello")
36+
found : "hello".type (with underlying type String)
3737
required: anotherint
3838
(which expands to) Int
3939
val bogus: anotherint = "hello"

test/files/neg/any-vs-anyref.check

+1-33
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,3 @@
1-
any-vs-anyref.scala:6: error: type mismatch;
2-
found : a.type (with underlying type A)
3-
required: AnyRef
4-
Note that A is bounded only by Equals, which means AnyRef is not a known parent.
5-
Such types can participate in value classes, but instances
6-
cannot appear in singleton types or in reference comparisons.
7-
def foo1[A <: Product](a: A) = { type X = a.type }
8-
^
9-
any-vs-anyref.scala:7: error: type mismatch;
10-
found : a.type (with underlying type A)
11-
required: AnyRef
12-
Note that A is bounded only by Product, Quux, which means AnyRef is not a known parent.
13-
Such types can participate in value classes, but instances
14-
cannot appear in singleton types or in reference comparisons.
15-
def foo2[A <: Product with Quux](a: A) = { type X = a.type }
16-
^
17-
any-vs-anyref.scala:8: error: type mismatch;
18-
found : a.type (with underlying type Product)
19-
required: AnyRef
20-
Note that Product extends Any, not AnyRef.
21-
Such types can participate in value classes, but instances
22-
cannot appear in singleton types or in reference comparisons.
23-
def foo3(a: Product) = { type X = a.type }
24-
^
25-
any-vs-anyref.scala:9: error: type mismatch;
26-
found : Product with Quux
27-
required: AnyRef
28-
Note that the parents of this type (Product, Quux) extend Any, not AnyRef.
29-
Such types can participate in value classes, but instances
30-
cannot appear in singleton types or in reference comparisons.
31-
def foo4(a: Product with Quux) = { type X = a.type }
32-
^
331
any-vs-anyref.scala:10: error: value eq is not a member of Quux with Product
342
Note that the parents of this type (Quux, Product) extend Any, not AnyRef.
353
Such types can participate in value classes, but instances
@@ -77,4 +45,4 @@ any-vs-anyref.scala:27: error: type mismatch;
7745
required: Quux{def g(x: Int): Int}
7846
f(new Quux { def g(x: String) = x })
7947
^
80-
11 errors found
48+
7 errors found

0 commit comments

Comments
 (0)