Skip to content

Add subtype annotations #4625

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

Closed
wants to merge 15 commits into from
Closed
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/backend/jvm/CollectEntryPoints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ object CollectEntryPoints{
def isJavaMainMethod(sym: Symbol)(implicit ctx: Context) = {
(sym.name == nme.main) && (sym.info match {
case r@MethodTpe(_, List(defn.ArrayOf(t)), _) =>
(t.widenDealias =:= defn.StringType) && (
r.resultType.widenDealias =:= defn.UnitType)
(t.widenDealiasStripAnnots =:= defn.StringType) && (
r.resultType.widenDealiasStripAnnots =:= defn.UnitType)
case _ => false
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma

def members: List[Symbol] = tp.allMembers.map(_.symbol).toList

def typeSymbol: Symbol = tp.widenDealias.typeSymbol
def typeSymbol: Symbol = tp.widenDealiasStripAnnots.typeSymbol

def =:=(other: Type): Boolean = tp =:= other

Expand Down Expand Up @@ -932,7 +932,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
ObjectReference.asInstanceOf[ct.bTypes.ClassBType]
}

tp.widenDealias match {
tp.widenDealiasStripAnnots match {
case JavaArrayType(el) =>ArrayBType(el.toTypeKind(ct)(storage)) // Array type such as Array[Int] (kept by erasure)
case t: TypeRef =>
t.info match {
Expand Down Expand Up @@ -1190,8 +1190,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
val t = field.tpt.tpe.typeSymbol
if (t.exists) t
else {
val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size
val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass
val arity = field.meth.tpe.widenDealiasStripAnnots.paramTypes.size - _1.size
val returnsUnit = field.meth.tpe.widenDealiasStripAnnots.resultType.classSymbol == UnitClass
if (returnsUnit)
ctx.requiredClass(("scala.compat.java8.JProcedure" + arity).toTermName)
else ctx.requiredClass(("scala.compat.java8.JFunction" + arity).toTermName)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/backend/jvm/scalaPrimitives.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class DottyPrimitives(ctx: Context) {
case _ => getPrimitive(fun)
}

def elementType: Type = tpe.widenDealias match {
def elementType: Type = tpe.widenDealiasStripAnnots match {
case defn.ArrayOf(el) => el
case JavaArrayType(el) => el
case _ =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ object desugar {
case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) =>
val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next()
var local = defctx.denotNamed(tp.name ++ suffix).suchThat(_.isParamOrAccessor).symbol
if (local.exists) (defctx.owner.thisType select local).dealias
if (local.exists) (defctx.owner.thisType select local).dealiasKeepAnnots
else {
def msg =
s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope.toList}"
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
/** An extractor for def of a closure contained the block of the closure. */
object closureDef {
def unapply(tree: Tree): Option[DefDef] = tree match {
case Block(Nil, expr) => unapply(expr)
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, closure: Closure) =>
Some(meth)
case _ => None
Expand Down Expand Up @@ -690,7 +691,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
*/
def isStructuralTermSelect(tree: Tree)(implicit ctx: Context) = tree match {
case tree: Select =>
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match {
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealiasStripAnnots match {
case RefinedType(parent, rname, rinfo) =>
rname == tree.name || hasRefinement(parent)
case tp: TypeProxy =>
Expand Down
25 changes: 25 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,31 @@ object Trees {

override def toText(printer: Printer) = printer.toText(this)

def sameTree(that: Tree[_]): Boolean = {
def isSame(x: Any, y: Any): Boolean =
x.asInstanceOf[AnyRef].eq(y.asInstanceOf[AnyRef]) || {
x match {
case x: Tree[_] =>
y match {
case y: Tree[_] => x.sameTree(y)
case _ => false
}
case x: List[_] =>
y match {
case y: List[_] => x.corresponds(y)(isSame)
case _ => false
}
case _ =>
false
}
}
this.getClass == that.getClass && {
val it1 = this.productIterator
val it2 = that.productIterator
it1.corresponds(it2)(isSame)
}
}

override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]

Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Ident(tp)
else {
val pre = tp.prefix
if (pre.isSingleton) followOuterLinks(singleton(pre.dealias)).select(tp)
if (pre.isSingleton) followOuterLinks(singleton(pre.dealiasStripAnnots)).select(tp)
else Select(TypeTree(pre), tp)
}

Expand Down Expand Up @@ -791,7 +791,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
applyOverloaded(tree, nme.EQ, that :: Nil, Nil, defn.BooleanType)

/** `tree.isInstanceOf[tp]`, with special treatment of singleton types */
def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealias match {
def isInstance(tp: Type)(implicit ctx: Context): Tree = tp.dealiasStripAnnots match {
case tp: SingletonType =>
if (tp.widen.derivesFrom(defn.ObjectClass))
tree.ensureConforms(defn.ObjectType).select(defn.Object_eq).appliedTo(singleton(tp))
Expand Down Expand Up @@ -963,7 +963,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val alternatives = ctx.typer.resolveOverloaded(allAlts, proto)
assert(alternatives.size == 1,
i"${if (alternatives.isEmpty) "no" else "multiple"} overloads available for " +
i"$method on ${receiver.tpe.widenDealias} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." +
i"$method on ${receiver.tpe.widenDealiasKeepAnnots} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." +
i" isAnnotConstructor = $isAnnotConstructor.\n" +
i"all alternatives: ${allAlts.map(_.symbol.showDcl).mkString(", ")}\n" +
i"matching alternatives: ${alternatives.map(_.symbol.showDcl).mkString(", ")}.") // this is parsed from bytecode tree. there's nothing user can do about it
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {

case class Inline() extends Mod(Flags.Inline)

case class Transparent() extends Mod(Flags.Transparent)

case class Enum() extends Mod(Flags.Enum)
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ object Annotations {
def isEvaluated: Boolean = true

def ensureCompleted(implicit ctx: Context): Unit = tree

def sameAnnotation(that: Annotation)(implicit ctx: Context) =
symbol == that.symbol && tree.sameTree(that.tree)
}

case class ConcreteAnnotation(t: Tree) extends Annotation {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class CheckRealizable(implicit ctx: Context) {
private def isLateInitialized(sym: Symbol) = sym.is(Lazy, butNot = Module)

/** The realizability status of given type `tp`*/
def realizability(tp: Type): Realizability = tp.dealias match {
def realizability(tp: Type): Realizability = tp.dealiasStripAnnots match {
case tp: TermRef =>
val sym = tp.symbol
if (sym.is(Stable)) realizability(tp.prefix)
Expand All @@ -85,7 +85,7 @@ class CheckRealizable(implicit ctx: Context) {
case _: SingletonType | NoPrefix =>
Realizable
case tp =>
def isConcrete(tp: Type): Boolean = tp.dealias match {
def isConcrete(tp: Type): Boolean = tp.dealiasStripAnnots match {
case tp: TypeRef => tp.symbol.isClass
case tp: TypeProxy => isConcrete(tp.underlying)
case tp: AndType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
Expand All @@ -96,7 +96,7 @@ class CheckRealizable(implicit ctx: Context) {
else boundsRealizability(tp).andAlso(memberRealizability(tp))
}

private def refinedNames(tp: Type): Set[Name] = tp.dealias match {
private def refinedNames(tp: Type): Set[Name] = tp.dealiasStripAnnots match {
case tp: RefinedType => refinedNames(tp.parent) + tp.refinedName
case tp: AndType => refinedNames(tp.tp1) ++ refinedNames(tp.tp2)
case tp: OrType => refinedNames(tp.tp1) ++ refinedNames(tp.tp2)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Constants.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ object Constants {
/** Convert constant value to conform to given type.
*/
def convertTo(pt: Type)(implicit ctx: Context): Constant = {
def classBound(pt: Type): Type = pt.dealias.stripTypeVar match {
def classBound(pt: Type): Type = pt.dealiasStripAnnots.stripTypeVar match {
case tref: TypeRef if !tref.symbol.isClass && tref.info.exists =>
classBound(tref.info.bounds.lo)
case param: TypeParamRef =>
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ trait ConstraintHandling {
private def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean =
!constraint.contains(param) || {
def occursIn(bound: Type): Boolean = {
val b = bound.dealias
val b = bound.dealiasStripAnnots
(b eq param) || {
b match {
case b: AndType => occursIn(b.tp1) || occursIn(b.tp2)
Expand Down Expand Up @@ -275,7 +275,7 @@ trait ConstraintHandling {
case tp: OrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
case _ => true
}
def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
def isOrType(tp: Type): Boolean = tp.dealiasStripAnnots match {
case tp: OrType => true
case tp: RefinedOrRecType => isOrType(tp.parent)
case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)
Expand Down
20 changes: 11 additions & 9 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@ class Definitions {
def ClassfileAnnotationClass(implicit ctx: Context) = ClassfileAnnotationType.symbol.asClass
lazy val StaticAnnotationType = ctx.requiredClassRef("scala.annotation.StaticAnnotation")
def StaticAnnotationClass(implicit ctx: Context) = StaticAnnotationType.symbol.asClass
lazy val SubTypeAnnotationType = ctx.requiredClassRef("scala.annotation.SubTypeAnnotation")
def SubTypeAnnotationClass(implicit ctx: Context) = SubTypeAnnotationType.symbol.asClass

// Annotation classes
lazy val AliasAnnotType = ctx.requiredClassRef("scala.annotation.internal.Alias")
Expand Down Expand Up @@ -795,7 +797,7 @@ class Definitions {
def unapply(ft: Type)(implicit ctx: Context) = {
val tsym = ft.typeSymbol
if (isFunctionClass(tsym)) {
val targs = ft.dealias.argInfos
val targs = ft.dealiasStripAnnots.argInfos
if (targs.isEmpty) None
else Some(targs.init, targs.last, tsym.name.isImplicitFunction, tsym.name.isErasedFunction)
}
Expand All @@ -808,7 +810,7 @@ class Definitions {
PartialFunctionType.appliedTo(arg :: result :: Nil)
def unapply(pft: Type)(implicit ctx: Context) = {
if (pft.isRef(PartialFunctionClass)) {
val targs = pft.dealias.argInfos
val targs = pft.dealiasStripAnnots.argInfos
if (targs.length == 2) Some((targs.head, targs.tail)) else None
}
else None
Expand All @@ -819,7 +821,7 @@ class Definitions {
def apply(elem: Type)(implicit ctx: Context) =
if (ctx.erasedTypes) JavaArrayType(elem)
else ArrayType.appliedTo(elem :: Nil)
def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match {
def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealiasStripAnnots match {
case AppliedType(at, arg :: Nil) if at isRef ArrayType.symbol => Some(arg)
case _ => None
}
Expand All @@ -840,7 +842,7 @@ class Definitions {
if (ndims == 0) elem else ArrayOf(apply(elem, ndims - 1))
def unapply(tp: Type)(implicit ctx: Context): Option[(Type, Int)] = tp match {
case ArrayOf(elemtp) =>
def recur(elemtp: Type): Option[(Type, Int)] = elemtp.dealias match {
def recur(elemtp: Type): Option[(Type, Int)] = elemtp.dealiasStripAnnots match {
case TypeBounds(lo, hi) => recur(hi)
case MultiArrayOf(finalElemTp, n) => Some(finalElemTp, n + 1)
case _ => Some(elemtp, 1)
Expand Down Expand Up @@ -1020,7 +1022,7 @@ class Definitions {
(sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf)

def isTupleType(tp: Type)(implicit ctx: Context) = {
val arity = tp.dealias.argInfos.length
val arity = tp.dealiasStripAnnots.argInfos.length
arity <= MaxTupleArity && TupleType(arity) != null && (tp isRef TupleType(arity).symbol)
}

Expand All @@ -1036,7 +1038,7 @@ class Definitions {
*/
def isNonDepFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
val sym = tp.dealias.typeSymbol
val sym = tp.dealiasStripAnnots.typeSymbol
arity >= 0 && isFunctionClass(sym) && tp.isRef(FunctionType(arity, sym.name.isImplicitFunction, sym.name.isErasedFunction).typeSymbol)
}

Expand Down Expand Up @@ -1082,7 +1084,7 @@ class Definitions {
false
})

def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
def functionArity(tp: Type)(implicit ctx: Context) = tp.dealiasStripAnnots.argInfos.length - 1

/** Return underlying immplicit function type (i.e. instance of an ImplicitFunctionN class)
* or NoType if none exists. The following types are considered as underlying types:
Expand All @@ -1091,7 +1093,7 @@ class Definitions {
* - the upper bound of a TypeParamRef in the current constraint
*/
def asImplicitFunctionType(tp: Type)(implicit ctx: Context): Type =
tp.stripTypeVar.dealias match {
tp.stripTypeVar.dealiasStripAnnots match {
case tp1: TypeParamRef if ctx.typerState.constraint.contains(tp1) =>
asImplicitFunctionType(ctx.typeComparer.bounds(tp1).hiBound)
case tp1 =>
Expand All @@ -1104,7 +1106,7 @@ class Definitions {
asImplicitFunctionType(tp).exists

def isErasedFunctionType(tp: Type)(implicit ctx: Context) =
isFunctionType(tp) && tp.dealias.typeSymbol.name.isErasedFunction
isFunctionType(tp) && tp.dealiasStripAnnots.typeSymbol.name.isErasedFunction

// ----- primitive value class machinery ------------------------------------------

Expand Down
25 changes: 17 additions & 8 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,10 @@ object Flags {
/** Symbol is a Java default method */
final val DefaultMethod = termFlag(38, "<defaultmethod>")

/** Symbol is a Java enum */
/** Labelled with `transparent` modifier */
final val Transparent = termFlag(39, "transparent")

/** Symbol is an enum class or enum case (if used with case) */
final val Enum = commonFlag(40, "<enum>")

/** Labeled with `erased` modifier (erased value) */
Expand Down Expand Up @@ -436,7 +439,7 @@ object Flags {

/** Flags representing source modifiers */
final val SourceModifierFlags =
commonFlags(Private, Protected, Abstract, Final, Inline,
commonFlags(Private, Protected, Abstract, Final, Inline, Transparent,
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic, Erased)

/** Flags representing modifiers that can appear in trees */
Expand All @@ -457,7 +460,7 @@ object Flags {
Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic |
CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags |
NonMember | ImplicitCommon | Permanent | Synthetic |
SuperAccessorOrScala2x | Inline
SuperAccessorOrScala2x | Inline | Transparent.toCommonFlags

/** Flags that are not (re)set when completing the denotation, or, if symbol is
* a top-level class or object, when completing the denotation once the class
Expand Down Expand Up @@ -513,7 +516,7 @@ object Flags {
/** Flags that can apply to a module val */
final val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
Override | Final | Method | Implicit | Lazy |
Accessor | AbsOverride | Stable | Captured | Synchronized | Inline | Erased
Accessor | AbsOverride | Stable | Captured | Synchronized | Erased

/** Flags that can apply to a module class */
final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | ImplClass | Enum
Expand Down Expand Up @@ -548,8 +551,8 @@ object Flags {
/** Either method or lazy or deferred */
final val MethodOrLazyOrDeferred = Method | Lazy | Deferred

/** Labeled `private`, `final`, or `inline` */
final val PrivateOrFinalOrInline = Private | Final | Inline
/** Labeled `private`, `final`, `inline`, or `transparent` */
final val EffectivelyFinal = Private | Final | Inline | Transparent.toCommonFlags

/** A private method */
final val PrivateMethod = allOf(Private, Method)
Expand All @@ -560,6 +563,9 @@ object Flags {
/** An inline method */
final val InlineMethod = allOf(Inline, Method)

/** An transparent method */
final val TransparentMethod = allOf(Transparent, Method)

/** An inline parameter */
final val InlineParam = allOf(Inline, Param)

Expand All @@ -575,6 +581,9 @@ object Flags {
/** An accessor or label */
final val AccessorOrLabel = Accessor | Label

/** An accessor or a synthetic symbol */
final val AccessorOrSynthetic = Accessor | Synthetic

/** A synthetic or private definition */
final val SyntheticOrPrivate = Synthetic | Private

Expand All @@ -584,8 +593,8 @@ object Flags {
/** A deferred type member or parameter (these don't have right hand sides) */
final val DeferredOrTypeParam = Deferred | TypeParam

/** value that's final or inline */
final val FinalOrInline = Final | Inline
/** value that's final, inline, or transparent */
final val FinalOrInlineOrTransparent = Final | Inline | Transparent.toCommonFlags

/** A covariant type parameter instance */
final val LocalCovariant = allOf(Local, Covariant)
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Mode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,4 @@ object Mode {

/** We are in the IDE */
val Interactive = newMode(20, "Interactive")

}
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
* that are not top-level are not affected.
*/
def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): OrderingConstraint = {
val replacement = tp.dealias.stripTypeVar
val replacement = tp.dealiasKeepAnnots.stripTypeVar
if (param == replacement) this
else {
assert(replacement.isValueTypeOrLambda)
Expand Down
Loading