aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-06-29 19:05:20 +0200
committerMartin Odersky <odersky@gmail.com>2016-07-11 13:34:59 +0200
commitaf43d325b778973ad9e144b5c27c455febb98890 (patch)
tree7803923eade05a15f0a5bbe3ef8b6fb86390643b /src/dotty
parent850dc6f2fb3b6228f2586ce0790621e80f664afe (diff)
downloaddotty-af43d325b778973ad9e144b5c27c455febb98890.tar.gz
dotty-af43d325b778973ad9e144b5c27c455febb98890.tar.bz2
dotty-af43d325b778973ad9e144b5c27c455febb98890.zip
Abstract type parameters out from type symbols
In the new hk scheme, a type parameter can be represented by a refinement without a corresponding symbol. Therefore, we need to disentangle the info inherent in a type parameter from the contents of a type symbol. We achieve this by creating a common super trait "MemerInfo" of Symbol and RefinedType.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/core/MemberBinding.scala34
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala9
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala32
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala43
-rw-r--r--src/dotty/tools/dotc/core/Types.scala19
-rw-r--r--src/dotty/tools/dotc/core/classfile/ClassfileParser.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala6
10 files changed, 110 insertions, 43 deletions
diff --git a/src/dotty/tools/dotc/core/MemberBinding.scala b/src/dotty/tools/dotc/core/MemberBinding.scala
new file mode 100644
index 000000000..6f081c542
--- /dev/null
+++ b/src/dotty/tools/dotc/core/MemberBinding.scala
@@ -0,0 +1,34 @@
+package dotty.tools.dotc.core
+
+import Names.Name
+import Contexts.Context
+import Types.{Type, TypeBounds}
+
+/** A common super trait of Symbol and Refinement.
+ * Used to capture the attributes of type parameters
+ * which can be implemented as either symbols or refinements.
+ */
+trait MemberBinding {
+
+ /** Does this binding represent a type parameter?
+ * Only in that case the rest of the binding's methods are significant.
+ */
+ def isTypeParam(implicit ctx: Context): Boolean
+
+ /** The name of the member */
+ def memberName(implicit ctx: Context): Name
+
+ /** The info of the member */
+ def memberBounds(implicit ctx: Context): TypeBounds
+
+ /** The info of the member as seen from a prefix type.
+ * This can be different from `memberInfo` if the binding
+ * is a type symbol of a class.
+ */
+ def memberBoundsAsSeenFrom(pre: Type)(implicit ctx: Context): TypeBounds
+
+ /** The variance of the type parameter
+ * @pre: isTypeParam = true
+ */
+ def memberVariance(implicit ctx: Context): Int
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 1b605e24f..c7eb54812 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -367,7 +367,7 @@ object Symbols {
* @param coord The coordinates of the symbol (a position or an index)
* @param id A unique identifier of the symbol (unique per ContextBase)
*/
- class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with printing.Showable {
+ class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with MemberBinding with printing.Showable {
type ThisName <: Name
@@ -489,6 +489,13 @@ object Symbols {
*/
def pos: Position = if (coord.isPosition) coord.toPosition else NoPosition
+ // MemberBinding methods
+ def isTypeParam(implicit ctx: Context) = denot.is(TypeParam)
+ def memberName(implicit ctx: Context): Name = name
+ def memberBounds(implicit ctx: Context) = denot.info.bounds
+ def memberBoundsAsSeenFrom(pre: Type)(implicit ctx: Context) = pre.memberInfo(this).bounds
+ def memberVariance(implicit ctx: Context) = denot.variance
+
// -------- Printing --------------------------------------------------------
/** The prefix string to be used when displaying this symbol without denotation */
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index bd115fefb..d9521b3c8 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -75,10 +75,10 @@ object TypeApplications {
/** Does the variance of `sym1` conform to the variance of `sym2`?
* This is the case if the variances are the same or `sym` is nonvariant.
*/
- def varianceConforms(sym1: TypeSymbol, sym2: TypeSymbol)(implicit ctx: Context) =
- sym1.variance == sym2.variance || sym2.variance == 0
+ def varianceConforms(sym1: MemberBinding, sym2: MemberBinding)(implicit ctx: Context) =
+ sym1.memberVariance == sym2.memberVariance || sym2.memberVariance == 0
- def variancesConform(syms1: List[TypeSymbol], syms2: List[TypeSymbol])(implicit ctx: Context) =
+ def variancesConform(syms1: List[MemberBinding], syms2: List[MemberBinding])(implicit ctx: Context) =
syms1.corresponds(syms2)(varianceConforms)
/** Extractor for
@@ -143,7 +143,7 @@ object TypeApplications {
object EtaExpansion {
def apply(tycon: TypeRef)(implicit ctx: Context) = {
assert(tycon.isEtaExpandable)
- tycon.EtaExpand(tycon.typeParams)
+ tycon.EtaExpand(tycon.typeParamSymbols)
}
def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = {
@@ -280,7 +280,7 @@ class TypeApplications(val self: Type) extends AnyVal {
* with the bounds on its hk args. See `LambdaAbstract`, where these
* types get introduced, and see `isBoundedLambda` below for the test.
*/
- final def typeParams(implicit ctx: Context): List[TypeSymbol] = /*>|>*/ track("typeParams") /*<|<*/ {
+ final def typeParams(implicit ctx: Context): List[MemberBinding] = /*>|>*/ track("typeParams") /*<|<*/ {
self match {
case self: ClassInfo =>
self.cls.typeParams
@@ -309,7 +309,7 @@ class TypeApplications(val self: Type) extends AnyVal {
val sym = self.parent.classSymbol
if (sym.isLambdaTrait) return sym.typeParams
}
- self.parent.typeParams.filterNot(_.name == self.refinedName)
+ self.parent.typeParams.filterNot(_.memberName == self.refinedName)
case self: SingletonType =>
Nil
case self: TypeProxy =>
@@ -319,6 +319,12 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}
+ final def typeParamSymbols(implicit ctx: Context): List[TypeSymbol] = {
+ val tparams = typeParams
+ assert(tparams.isEmpty || tparams.head.isInstanceOf[Symbol])
+ tparams.asInstanceOf[List[TypeSymbol]]
+ }
+
/** The named type parameters declared or inherited by this type.
* These are all uninstantiated named type parameters of this type or one
* of its base types.
@@ -498,7 +504,7 @@ class TypeApplications(val self: Type) extends AnyVal {
* v1 is compatible with v2, if v1 = v2 or v2 is non-variant.
*/
def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = {
- val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParams
+ val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParamSymbols
self.appliedTo(tparams map (_.typeRef)).LambdaAbstract(tparamsToUse)
//.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}")
}
@@ -508,7 +514,7 @@ class TypeApplications(val self: Type) extends AnyVal {
case self: RefinedType =>
self.derivedRefinedType(self.parent.EtaExpandCore, self.refinedName, self.refinedInfo)
case _ =>
- self.EtaExpand(self.typeParams)
+ self.EtaExpand(self.typeParamSymbols)
}
/** Eta expand if `self` is a (non-lambda) class reference and `bound` is a higher-kinded type */
@@ -621,12 +627,12 @@ class TypeApplications(val self: Type) extends AnyVal {
* @param args = `U1, ..., Un`
* @param tparams are assumed to be the type parameters of `T`.
*/
- final def appliedTo(args: List[Type], typParams: List[TypeSymbol])(implicit ctx: Context): Type = {
- def matchParams(t: Type, tparams: List[TypeSymbol], args: List[Type])(implicit ctx: Context): Type = args match {
+ final def appliedTo(args: List[Type], typParams: List[MemberBinding])(implicit ctx: Context): Type = {
+ def matchParams(t: Type, tparams: List[MemberBinding], args: List[Type])(implicit ctx: Context): Type = args match {
case arg :: args1 =>
try {
val tparam :: tparams1 = tparams
- matchParams(RefinedType(t, tparam.name, arg.toBounds(tparam)), tparams1, args1)
+ matchParams(RefinedType(t, tparam.memberName, arg.toBounds(tparam)), tparams1, args1)
} catch {
case ex: MatchError =>
println(s"applied type mismatch: $self $args, typeParams = $typParams") // !!! DEBUG
@@ -667,11 +673,11 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Turn this type, which is used as an argument for
* type parameter `tparam`, into a TypeBounds RHS
*/
- final def toBounds(tparam: Symbol)(implicit ctx: Context): TypeBounds = self match {
+ final def toBounds(tparam: MemberBinding)(implicit ctx: Context): TypeBounds = self match {
case self: TypeBounds => // this can happen for wildcard args
self
case _ =>
- val v = tparam.variance
+ val v = tparam.memberVariance
/* Not neeeded.
if (v > 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.upper(self)
else if (v < 0 && !(tparam is Local) && !(tparam is ExpandedTypeParam)) TypeBounds.lower(self)
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 9909c9e8a..58c6bea3a 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -534,7 +534,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* - the type parameters of `B` match one-by-one the variances of `tparams`,
* - `B` satisfies predicate `p`.
*/
- private def testLifted(tp1: Type, tp2: Type, tparams: List[TypeSymbol], p: Type => Boolean): Boolean = {
+ private def testLifted(tp1: Type, tp2: Type, tparams: List[MemberBinding], p: Type => Boolean): Boolean = {
val classBounds = tp2.member(tpnme.hkApply).info.classSymbols
def recur(bcs: List[ClassSymbol]): Boolean = bcs match {
case bc :: bcs1 =>
@@ -647,7 +647,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
}
}
- /** Replace any top-level recursive type `{ z => T }` in `tp` with
+ /** Replace any top-level recursive type `{ z => T }` in `tp` with
* `[z := anchor]T`.
*/
private def fixRecs(anchor: SingletonType, tp: Type): Type = {
@@ -726,24 +726,31 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
val rebindNeeded = tp2.refinementRefersToThis
val base = if (rebindNeeded) ensureStableSingleton(tp1) else tp1
val rinfo2 = if (rebindNeeded) tp2.refinedInfo.substRefinedThis(tp2, base) else tp2.refinedInfo
+ val mbr = base.member(name)
+
def qualifies(m: SingleDenotation) = isSubType(m.info, rinfo2)
- def memberMatches(mbr: Denotation): Boolean = mbr match { // inlined hasAltWith for performance
+
+ def memberMatches: Boolean = mbr match { // inlined hasAltWith for performance
case mbr: SingleDenotation => qualifies(mbr)
case _ => mbr hasAltWith qualifies
}
- /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
- memberMatches(base member name) ||
- tp1.isInstanceOf[SingletonType] &&
- { // special case for situations like:
- // class C { type T }
- // val foo: C
- // foo.type <: C { type T = foo.T }
- rinfo2 match {
- case rinfo2: TypeAlias =>
- !defn.isBottomType(base.widen) && (base select name) =:= rinfo2.alias
- case _ => false
- }
- }
+
+ // special case for situations like:
+ // class C { type T }
+ // val foo: C
+ // foo.type <: C { type T = foo.T }
+ def selfReferentialMatch = tp1.isInstanceOf[SingletonType] && {
+ rinfo2 match {
+ case rinfo2: TypeAlias =>
+ !defn.isBottomType(base.widen) && (base select name) =:= rinfo2.alias
+ case _ => false
+ }
+ }
+
+ def varianceMatches = true // TODO: fill in
+
+ /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${mbr.info.show} $rinfo2", subtyping) /*<|<*/ {
+ (memberMatches || selfReferentialMatch) && varianceMatches
}
}
@@ -1117,8 +1124,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
* in where we allow which interpretation.
*/
private def liftIfHK(tp1: Type, tp2: Type, op: (Type, Type) => Type) = {
- val tparams1 = tp1.typeParams
- val tparams2 = tp2.typeParams
+ val tparams1 = tp1.typeParamSymbols // TODO revise for new hk scheme
+ val tparams2 = tp2.typeParamSymbols
def onlyNamed(tparams: List[TypeSymbol]) = tparams.forall(!_.is(ExpandedName))
if (tparams1.isEmpty || tparams2.isEmpty ||
onlyNamed(tparams1) && onlyNamed(tparams2)) op(tp1, tp2)
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 5252a9149..cba13ef81 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -869,7 +869,7 @@ object Types {
def isParamName = tp.classSymbol.typeParams.exists(_.name == tp.refinedName)
if (refinementOK || isParamName) tp.underlying.underlyingClassRef(refinementOK)
else NoType
- case tp: RecType if refinementOK => tp.parent
+ case tp: RecType if refinementOK => tp.parent
case _ => NoType
}
@@ -2051,7 +2051,7 @@ object Types {
* given the refined type itself.
*/
abstract case class RefinedType(private var myParent: Type, refinedName: Name, private var myRefinedInfo: Type)
- extends RefinedOrRecType with BindingType {
+ extends RefinedOrRecType with BindingType with MemberBinding {
final def parent = myParent
final def refinedInfo = myRefinedInfo
@@ -2090,6 +2090,16 @@ object Types {
if (parent.member(refinedName).exists) derivedRefinedType(parent, refinedName, refinedInfo)
else parent
+ // MemberBinding methods
+ def isTypeParam(implicit ctx: Context) = refinedInfo match {
+ case tp: TypeBounds => tp.isBinding
+ case _ => false
+ }
+ def memberName(implicit ctx: Context) = refinedName
+ def memberBounds(implicit ctx: Context) = refinedInfo.bounds
+ def memberBoundsAsSeenFrom(pre: Type)(implicit ctx: Context) = memberBounds
+ def memberVariance(implicit ctx: Context) = BindingKind.toVariance(refinedInfo.bounds.bindingKind)
+
override def equals(that: Any) = that match {
case that: RefinedType =>
this.parent == that.parent &&
@@ -3120,7 +3130,10 @@ object Types {
object BindingKind {
def fromVariance(v: Int): BindingKind = new BindingKind((v + NonvariantBinding.n).toByte)
- def toVariance(bk: BindingKind): Int = bk.n
+ def toVariance(bk: BindingKind): Int = {
+ assert(bk.n != 0)
+ bk.n - NonvariantBinding.n
+ }
}
// ----- Annotated and Import types -----------------------------------------------
diff --git a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index f7a69aa53..2d7b037b1 100644
--- a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -272,7 +272,7 @@ class ClassfileParser(
if (sig(index) == '<') {
accept('<')
var tp1: Type = tp
- var formals = tp.typeParams
+ var formals = tp.typeParamSymbols
while (sig(index) != '>') {
sig(index) match {
case variance @ ('+' | '-' | '*') =>
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 7de40294d..e21a08fb8 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -325,7 +325,7 @@ trait ImplicitRunInfo { self: RunInfo =>
}
def addParentScope(parent: TypeRef): Unit = {
iscopeRefs(parent) foreach addRef
- for (param <- parent.typeParams)
+ for (param <- parent.typeParamSymbols)
comps ++= iscopeRefs(tp.member(param.name).info)
}
val companion = cls.companionModule
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index a8f3b8918..8437b651c 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -989,7 +989,7 @@ class Namer { typer: Typer =>
if (args.nonEmpty) {
val tycon = tp.withoutArgs(args)
val tycon1 = this(tycon)
- val tparams = tycon.typeParams
+ val tparams = tycon.typeParamSymbols
val args1 = if (args.length == tparams.length) etaExpandIfHK(tparams, args) else args
if ((tycon1 eq tycon) && (args1 eq args)) tp else tycon1.appliedTo(args1)
} else mapOver(tp)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 47c3631b8..b7e2fd832 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -409,11 +409,11 @@ trait TypeAssigner {
def refineNamed(tycon: Type, arg: Tree) = arg match {
case ast.Trees.NamedArg(name, argtpt) =>
// Dotty deviation: importing ast.Trees._ and matching on NamedArg gives a cyclic ref error
- val tparam = tparams.find(_.name == name) match {
+ val tparam = tparams.find(_.memberName == name) match {
case Some(tparam) => tparam
case none => ntparams.find(_.name == name).getOrElse(NoSymbol)
}
- if (tparam.exists) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam))
+ if (tparam.isTypeParam) RefinedType(tycon, name, argtpt.tpe.toBounds(tparam))
else errorType(i"$tycon does not have a parameter or abstract type member named $name", arg.pos)
case _ =>
errorType(s"named and positional type arguments may not be mixed", arg.pos)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index fb3418563..225516503 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -943,14 +943,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
ctx.error(d"wrong number of type arguments for ${tpt1.tpe}, should be ${tparams.length}", tree.pos)
args = args.take(tparams.length)
}
- def typedArg(arg: untpd.Tree, tparam: Symbol) = {
+ def typedArg(arg: untpd.Tree, tparam: MemberBinding) = {
val (desugaredArg, argPt) =
if (ctx.mode is Mode.Pattern)
- (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.info)
+ (if (isVarPattern(arg)) desugar.patternVar(arg) else arg, tparam.memberBounds)
else
(arg, WildcardType)
val arg1 = typed(desugaredArg, argPt)
- adaptTypeArg(arg1, tparam.info)
+ adaptTypeArg(arg1, tparam.memberBounds)
}
args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
}