Skip to content

Commit 4231d7a

Browse files
committed
Merge pull request #147 from dotty-staging/transform/variance
transform/variance
2 parents 51eeac7 + d3f49de commit 4231d7a

24 files changed

+584
-49
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,18 @@ object desugar {
191191

192192
/** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows:
193193
*
194-
* class C[T]
194+
* class C[v T]
195195
* ==>
196-
* class C { type C$T; type T = C$T }
196+
* class C { type v C$T; type v T = C$T }
197197
*/
198198
def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = {
199199
val TypeDef(mods, name, rhs) = tdef
200200
if (mods is PrivateLocalParam) {
201201
val tparam = cpy.TypeDef(tdef,
202202
mods &~ PrivateLocal | ExpandedName, name.expandedName(ctx.owner), rhs, tdef.tparams)
203203
val alias = cpy.TypeDef(tdef,
204-
Modifiers(PrivateLocalParamAccessor | Synthetic), name, refOfDef(tparam))
204+
Modifiers(PrivateLocalParamAccessor | Synthetic | mods.flags & VarianceFlags),
205+
name, refOfDef(tparam))
205206
Thicket(tparam, alias)
206207
}
207208
else cpy.TypeDef(tdef, mods, name, rhs, tdef.tparams)
@@ -274,7 +275,13 @@ object desugar {
274275
// def _1 = this.p1
275276
// ...
276277
// def _N = this.pN
277-
// def copy(p1: T1 = p1, ..., pN: TN = pN)(moreParams) = new C[...](p1, ..., pN)(moreParams)
278+
// def copy(p1: T1 = p1: @uncheckedVariance, ...,
279+
// pN: TN = pN: @uncheckedVariance)(moreParams) =
280+
// new C[...](p1, ..., pN)(moreParams)
281+
//
282+
// Note: copy default parameters need @uncheckedVariance; see
283+
// neg/t1843-variances.scala for a test case. The test would give
284+
// two errors without @uncheckedVariance, one of them spurious.
278285
val caseClassMeths =
279286
if (mods is Case) {
280287
def syntheticProperty(name: TermName, rhs: Tree) =
@@ -289,8 +296,10 @@ object desugar {
289296
val copyMeths =
290297
if (mods is Abstract) Nil
291298
else {
299+
def copyDefault(vparam: ValDef) =
300+
makeAnnotated(defn.UncheckedVarianceAnnot, refOfDef(vparam))
292301
val copyFirstParams = derivedVparamss.head.map(vparam =>
293-
cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam)))
302+
cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, copyDefault(vparam)))
294303
val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
295304
cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree))
296305
DefDef(synthetic, nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr) :: Nil

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core._
66
import dotty.tools.dotc.transform.TypeUtils
77
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
88
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
9-
import CheckTrees._, Denotations._, Decorators._
9+
import Denotations._, Decorators._
1010
import config.Printers._
1111
import typer.ErrorReporting._
1212

@@ -134,7 +134,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
134134
TypeTree(original.tpe, original)
135135

136136
def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree =
137-
untpd.TypeTree(original).withType(tp).checked
137+
untpd.TypeTree(original).withType(tp)
138138

139139
def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree =
140140
ta.assignType(untpd.SingletonTypeTree(ref), ref)
@@ -237,7 +237,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
237237
val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy)
238238
.orElse(ctx.newLocalDummy(cls))
239239
val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body)
240-
.withType(localDummy.termRef).checked
240+
.withType(localDummy.termRef)
241241
ta.assignType(untpd.TypeDef(Modifiers(cls), cls.name, impl), cls)
242242
}
243243

@@ -354,11 +354,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
354354
case _ => false
355355
}
356356

357-
def checked(implicit ctx: Context): ThisTree = {
358-
if (ctx.settings.YcheckTypedTrees.value) checkType(tree)
359-
tree
360-
}
361-
362357
def shallowFold[T](z: T)(op: (T, tpd.Tree) => T) =
363358
new ShallowFolder(op).apply(z, tree)
364359

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ class Definitions {
196196
lazy val Array_update = ctx.requiredMethod(ArrayClass, nme.update)
197197
lazy val Array_length = ctx.requiredMethod(ArrayClass, nme.length)
198198
lazy val Array_clone = ctx.requiredMethod(ArrayClass, nme.clone_)
199-
lazy val uncheckedStableClass: ClassSymbol = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")
200199

201200
lazy val UnitClass = valueClassSymbol("scala.Unit", BoxedUnitClass, java.lang.Void.TYPE, UnitEnc)
202201
lazy val BooleanClass = valueClassSymbol("scala.Boolean", BoxedBooleanClass, java.lang.Boolean.TYPE, BooleanEnc)
@@ -296,6 +295,8 @@ class Definitions {
296295
lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
297296
lazy val ThrowsAnnot = ctx.requiredClass("scala.throws")
298297
lazy val UncheckedAnnot = ctx.requiredClass("scala.unchecked")
298+
lazy val UncheckedStableAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedStable")
299+
lazy val UncheckedVarianceAnnot = ctx.requiredClass("scala.annotation.unchecked.uncheckedVariance")
299300
lazy val VolatileAnnot = ctx.requiredClass("scala.volatile")
300301

301302
// convenient one-parameter method types

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ object Denotations {
619619
throw new StaleSymbol(msg)
620620
}
621621

622-
/** The period (interval of phases) for which there exists
622+
/** The period (interval of phases) for which there exists
623623
* a valid denotation in this flock.
624624
*/
625625
def coveredInterval(implicit ctx: Context): Period = {
@@ -641,11 +641,15 @@ object Denotations {
641641
*/
642642
def syncWithParents(implicit ctx: Context): SingleDenotation = this
643643

644+
/** Show declaration string; useful for showing declarations
645+
* as seen from subclasses.
646+
*/
647+
def showDcl(implicit ctx: Context): String = ctx.dclText(this).show
648+
644649
override def toString =
645650
if (symbol == NoSymbol) symbol.toString
646651
else s"<SingleDenotation of type $infoOrCompleter>"
647652

648-
649653
def definedPeriodsString: String = {
650654
var sb = new StringBuilder()
651655
var cur = this

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,9 @@ object Flags {
500500
/** A parameter or parameter accessor */
501501
final val ParamOrAccessor = Param | ParamAccessor
502502

503+
/** A type parameter or type parameter accessor */
504+
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
505+
503506
/** A covariant type parameter instance */
504507
final val LocalCovariant = allOf(Local, Covariant)
505508

@@ -521,6 +524,9 @@ object Flags {
521524
/** A Java companion object */
522525
final val JavaModule = allOf(JavaDefined, Module)
523526

527+
/** A Java companion object */
528+
final val JavaProtected = allOf(JavaDefined, Protected)
529+
524530
/** Labeled private[this] */
525531
final val PrivateLocal = allOf(Private, Local)
526532

src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ object NameOps {
7373
def isModuleClassName = name endsWith MODULE_SUFFIX
7474
def isImportName = name startsWith IMPORT
7575
def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED)
76+
def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0
7677

7778
def isModuleVarName(name: Name): Boolean =
7879
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
@@ -251,9 +252,12 @@ object NameOps {
251252

252253
/** If this is a default getter, its index (starting from 0), else -1 */
253254
def defaultGetterIndex: Int = {
254-
val p = name.indexOfSlice(DEFAULT_GETTER)
255-
if (p >= 0) name.drop(p + DEFAULT_GETTER.length).toString.toInt - 1
256-
else -1
255+
var i = name.length
256+
while (i > 0 && name(i - 1).isDigit) i -= 1
257+
if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
258+
name.drop(i).toString.toInt - 1
259+
else
260+
-1
257261
}
258262

259263
/** The name of an accessor for protected symbols. */

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ object SymDenotations {
402402
final def isStable(implicit ctx: Context) = {
403403
val isUnstable =
404404
(this is UnstableValue) ||
405-
ctx.isVolatile(info) && !hasAnnotation(defn.uncheckedStableClass)
405+
ctx.isVolatile(info) && !hasAnnotation(defn.UncheckedStableAnnot)
406406
(this is Stable) || isType || {
407407
if (isUnstable) false
408408
else { setFlag(Stable); true }
@@ -589,12 +589,22 @@ object SymDenotations {
589589
NoSymbol
590590
}
591591

592-
/** The field accessed by this getter or setter */
593-
def accessedField(implicit ctx: Context): Symbol = {
592+
/** The field accessed by this getter or setter, or if it does not exist, the getter */
593+
def accessedFieldOrGetter(implicit ctx: Context): Symbol = {
594594
val fieldName = if (isSetter) name.asTermName.setterToGetter else name
595-
owner.info.decl(fieldName).suchThat(d => !(d is Method)).symbol
595+
val d = owner.info.decl(fieldName)
596+
val field = d.suchThat(!_.is(Method)).symbol
597+
def getter = d.suchThat(_.info.isParameterless).symbol
598+
field orElse getter
596599
}
597600

601+
/** The field accessed by a getter or setter, or
602+
* if it does not exists, the getter of a setter, or
603+
* if that does not exist the symbol itself.
604+
*/
605+
def underlyingSymbol(implicit ctx: Context): Symbol =
606+
if (is(Accessor)) accessedFieldOrGetter orElse symbol else symbol
607+
598608
/** The chain of owners of this denotation, starting with the denoting symbol itself */
599609
final def ownersIterator(implicit ctx: Context) = new Iterator[Symbol] {
600610
private[this] var current = symbol
@@ -723,17 +733,29 @@ object SymDenotations {
723733
denot.symbol
724734
}
725735

736+
/** If false, this symbol cannot possibly participate in an override,
737+
* either as overrider or overridee.
738+
*/
739+
final def canMatchInheritedSymbols(implicit ctx: Context): Boolean =
740+
maybeOwner.isClass && !isConstructor && !is(Private)
741+
726742
/** The symbol, in class `inClass`, that is overridden by this denotation. */
727743
final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
728-
if ((this is Private) && (owner ne inClass)) NoSymbol
744+
if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol
729745
else matchingSymbol(inClass, owner.thisType)
730746

731747
/** All symbols overriden by this denotation. */
732748
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
733-
if (exists && owner.isClass)
734-
owner.info.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
735-
else
736-
Iterator.empty
749+
if (!canMatchInheritedSymbols) Iterator.empty
750+
else overriddenFromType(owner.info)
751+
752+
/** Returns all all matching symbols defined in parents of the selftype. */
753+
final def extendedOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
754+
if (!canMatchInheritedSymbols) Iterator.empty
755+
else overriddenFromType(owner.asClass.classInfo.selfType)
756+
757+
private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
758+
tp.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
737759

738760
/** The symbol overriding this symbol in given subclass `ofclazz`.
739761
*
@@ -743,17 +765,6 @@ object SymDenotations {
743765
if (canMatchInheritedSymbols) matchingSymbol(inClass, inClass.thisType)
744766
else NoSymbol
745767

746-
/** If false, this symbol cannot possibly participate in an override,
747-
* either as overrider or overridee. For internal use; you should consult
748-
* with isOverridingSymbol. This is used by isOverridingSymbol to escape
749-
* the recursive knot.
750-
*/
751-
private def canMatchInheritedSymbols = (
752-
owner.isClass
753-
&& !this.isClass
754-
&& !this.isConstructor
755-
)
756-
757768
/** The symbol accessed by a super in the definition of this symbol when
758769
* seen from class `base`. This symbol is always concrete.
759770
* pre: `this.owner` is in the base class sequence of `base`.

src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,6 +2203,7 @@ object Types {
22032203
override def variance = 1
22042204
override def toString = "Co" + super.toString
22052205
}
2206+
22062207
final class ContraTypeBounds(lo: Type, hi: Type, hc: Int) extends CachedTypeBounds(lo, hi, hc) {
22072208
override def variance = -1
22082209
override def toString = "Contra" + super.toString

src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package dotty.tools.dotc
22
package printing
33

44
import core._
5-
import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._
5+
import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, Denotations._
66
import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation
77
import StdNames.nme
88
import ast.Trees._, ast.untpd
@@ -321,9 +321,13 @@ class PlainPrinter(_ctx: Context) extends Printer {
321321

322322
def annotsText(sym: Symbol): Text = Text(sym.annotations.map(toText))
323323

324-
def dclText(sym: Symbol): Text =
324+
def dclText(sym: Symbol): Text = dclTextWithInfo(sym, sym.unforcedInfo)
325+
326+
def dclText(d: SingleDenotation): Text = dclTextWithInfo(d.symbol, Some(d.info))
327+
328+
private def dclTextWithInfo(sym: Symbol, info: Option[Type]): Text =
325329
(toTextFlags(sym) ~~ keyString(sym) ~~
326-
(varianceString(sym) ~ nameString(sym)) ~ toTextRHS(sym.unforcedInfo)).close
330+
(varianceString(sym) ~ nameString(sym)) ~ toTextRHS(info)).close
327331

328332
def toText(sym: Symbol): Text =
329333
(kindString(sym) ~~ {

src/dotty/tools/dotc/printing/Printer.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package printing
44
import core._
55
import Texts._, ast.Trees._
66
import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant,
7-
Names.Name, Denotations.Denotation, Annotations.Annotation
7+
Names.Name, Denotations._, Annotations.Annotation
88

99
/** The base class of all printers
1010
*/
@@ -59,6 +59,9 @@ abstract class Printer {
5959
/** Textual representation of symbol's declaration */
6060
def dclText(sym: Symbol): Text
6161

62+
/** Textual representation of single denotation's declaration */
63+
def dclText(sd: SingleDenotation): Text
64+
6265
/** If symbol's owner is a printable class C, the text "in C", otherwise "" */
6366
def locationText(sym: Symbol): Text
6467

src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ object Erasure {
133133

134134
/** Generate a synthetic cast operation from tree.tpe to pt.
135135
*/
136-
def cast(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
136+
def cast(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
137+
// TODO: The commented out assertion fails for tailcall/t6574.scala
138+
// Fix the problem and enable the assertion.
139+
// assert(!pt.isInstanceOf[SingletonType], pt)
137140
if (pt isRef defn.UnitClass) unbox(tree, pt)
138141
else (tree.tpe, pt) match {
139142
case (defn.ArrayType(treeElem), defn.ArrayType(ptElem))
@@ -144,6 +147,7 @@ object Erasure {
144147
ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}")
145148
mkAsInstanceOf(tree, pt)
146149
}
150+
}
147151

148152
/** Adaptation of an expression `e` to an expected type `PT`, applying the following
149153
* rewritings exhaustively as long as the type of `e` is not a subtype of `PT`.

0 commit comments

Comments
 (0)