Skip to content

Fixes for various txxxx tickets #86

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

Merged
merged 22 commits into from
Mar 24, 2014
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*.class
*.log
*~

# sbt specific
dist/*
Expand Down
17 changes: 15 additions & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import core._
import Contexts._
import Periods._
import Symbols._
import Scopes._
import typer.{FrontEnd, Typer, Mode, ImportInfo}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
Expand All @@ -28,16 +29,28 @@ class Compiler {
runId += 1; runId
}

/** Produces the following contexts, from outermost to innermost
*
* bootStrap: A context with next available runId and a scope consisting of
* the RootPackage _root_
* start A context with RootClass as owner and the necessary initializations
* for type checking.
* imports For each element of RootImports, an import context
*/
def rootContext(implicit ctx: Context): Context = {
ctx.definitions.init(ctx)
ctx.usePhases(phases)
val start = ctx.fresh
val rootScope = new MutableScope
val bootstrap = ctx.fresh
.withPeriod(Period(nextRunId, FirstPhaseId))
.withScope(rootScope)
rootScope.enter(ctx.definitions.RootPackage)(bootstrap)
val start = bootstrap.fresh
.withOwner(defn.RootClass)
.withTyper(new Typer)
.withNewMode(Mode.ImplicitsEnabled)
.withTyperState(new MutableTyperState(ctx.typerState, new ConsoleReporter()(ctx), isCommittable = true))
ctx.definitions.init(start)
ctx.definitions.init(start) // set context of definitions to start
def addImport(ctx: Context, sym: Symbol) =
ctx.fresh.withImportInfo(ImportInfo.rootImport(sym)(ctx))
(start.withRunInfo(new RunInfo(start)) /: defn.RootImports)(addImport)
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ object Printers {
val unapp: Printer = noPrinter
val completions = noPrinter
val gadts = noPrinter
val hk = noPrinter
val incremental = noPrinter
val config = noPrinter
}
13 changes: 3 additions & 10 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,6 @@ class Definitions {
*/
def hkTrait(vcs: List[Int]) = {

def varianceSuffix(v: Int) = v match {
case -1 => "N"
case 0 => "I"
case 1 => "P"
}

def varianceFlags(v: Int) = v match {
case -1 => Contravariant
case 0 => Covariant
Expand All @@ -375,14 +369,13 @@ class Definitions {
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
val cls = denot.asClass.classSymbol
val paramDecls = newScope
for ((v, i) <- vcs.zipWithIndex)
newTypeParam(cls, tpnme.higherKindedParamName(i), varianceFlags(v), paramDecls)
for (i <- 0 until vcs.length)
newTypeParam(cls, tpnme.higherKindedParamName(i), EmptyFlags, paramDecls)
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, List(ObjectClass.typeRef), paramDecls)
}
}

val traitName =
tpnme.higherKindedTraitName(vcs.length) ++ (vcs map varianceSuffix).mkString
val traitName = tpnme.higherKindedTraitName(vcs)

def createTrait = {
val cls = newClassSymbol(
Expand Down
13 changes: 13 additions & 0 deletions src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ object NameOps {
}
}

/** The variances of the higherKinded parameters of the trait named
* by this name.
* @pre The name is a higher-kinded trait name, i.e. it starts with HK_TRAIT_PREFIX
*/
def hkVariances: List[Int] = {
def varianceOfSuffix(suffix: Char): Int = {
val idx = tpnme.varianceSuffixes.indexOf(suffix)
assert(idx >= 0)
idx - 1
}
name.drop(tpnme.HK_TRAIT_PREFIX.length).toList.map(varianceOfSuffix)
}

/** If name length exceeds allowable limit, replace part of it by hash */
def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString))
}
Expand Down
8 changes: 6 additions & 2 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ object StdNames {
val SPECIALIZED_INSTANCE: N = "specInstance$"
val THIS: N = "_$this"
val HK_PARAM_PREFIX: N = "_$hk$"
val HK_TRAIT_PREFIX: N = "$HigherKinded$"

final val Nil: N = "Nil"
final val Predef: N = "Predef"
Expand Down Expand Up @@ -281,7 +282,6 @@ object StdNames {
val ConstantType: N = "ConstantType"
val ExistentialTypeTree: N = "ExistentialTypeTree"
val Flag : N = "Flag"
val HigherKinded: N = "HigherKinded"
val Ident: N = "Ident"
val Import: N = "Import"
val Literal: N = "Literal"
Expand Down Expand Up @@ -645,10 +645,14 @@ object StdNames {
def syntheticTypeParamNames(num: Int): List[TypeName] =
(0 until num).map(syntheticTypeParamName)(breakOut)

def higherKindedTraitName(n: Int) = HigherKinded ++ n.toString
def higherKindedTraitName(vcs: List[Int]): TypeName = HK_TRAIT_PREFIX ++ vcs.map(varianceSuffix).mkString
def higherKindedParamName(n: Int) = HK_PARAM_PREFIX ++ n.toString

final val Conforms = encode("<:<")

def varianceSuffix(v: Int): Char = varianceSuffixes.charAt(v + 1)

val varianceSuffixes = "NIP"
}

abstract class JavaNames[N <: Name] extends DefinedNames[N] {
Expand Down
32 changes: 27 additions & 5 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import util.common._
import Names._
import Flags._
import util.Positions.Position
import config.Printers._
import collection.mutable

object TypeApplications {
Expand Down Expand Up @@ -137,6 +138,8 @@ class TypeApplications(val self: Type) extends AnyVal {
tp.underlying.appliedTo(args)
case AndType(l, r) =>
l.appliedTo(args) & r
case tp: PolyType =>
tp.instantiate(args)
case ErrorType =>
self
}
Expand Down Expand Up @@ -193,13 +196,32 @@ class TypeApplications(val self: Type) extends AnyVal {
NoType
}

/** The base type including all type arguments of this type.
/** The base type including all type arguments and applicable refinements
* of this type. Refinements are applicable if they refine a member of
* the parent type which furthermore is not a name-mangled type parameter.
* Existential types in arguments are returned as TypeBounds instances.
*/
final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = self.dealias match {
case AndType(tp1, tp2) => tp1.baseTypeWithArgs(base) & tp2.baseTypeWithArgs(base)
case OrType(tp1, tp2) => tp1.baseTypeWithArgs(base) | tp2.baseTypeWithArgs(base)
case _ => self.baseTypeRef(base).appliedTo(baseArgInfos(base))
final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) {
def default = self.baseTypeRef(base).appliedTo(baseArgInfos(base))
self match {
case tp: TypeRef =>
tp.info match {
case TypeBounds(_, hi) => hi.baseTypeWithArgs(base)
case _ => default
}
case tp @ RefinedType(parent, name) if !tp.member(name).symbol.is(ExpandedTypeParam) =>
val pbase = parent.baseTypeWithArgs(base)
if (pbase.member(name).exists) RefinedType(pbase, name, tp.refinedInfo)
else pbase
case tp: TermRef =>
tp.underlying.baseTypeWithArgs(base)
case AndType(tp1, tp2) =>
tp1.baseTypeWithArgs(base) & tp2.baseTypeWithArgs(base)
case OrType(tp1, tp2) =>
tp1.baseTypeWithArgs(base) | tp2.baseTypeWithArgs(base)
case _ =>
default
}
}

/** Translate a type of the form From[T] to To[T], keep other types as they are.
Expand Down
69 changes: 50 additions & 19 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ class TypeComparer(initctx: Context) extends DotClass {
def isNonBottomSubType(tp1: Type, tp2: Type): Boolean =
!(tp2 isRef NothingClass) && isSubType(tp1, tp2)

def isSubType(tp1: Type, tp2: Type): Boolean = /*>|>*/ ctx.traceIndented(s"isSubType ${tp1.show} <:< ${tp2.show}", subtyping) /*<|<*/ {
private def traceInfo(tp1: Type, tp2: Type) =
s"${tp1.show} <:< ${tp2.show}" +
(if (ctx.settings.verbose.value) s"${tp1.getClass} ${tp2.getClass}" else "")

def isSubType(tp1: Type, tp2: Type): Boolean = /*>|>*/ ctx.traceIndented(s"isSubType ${traceInfo(tp1, tp2)}", subtyping) /*<|<*/ {
if (tp2 eq NoType) false
else if (tp1 eq tp2) true
else {
Expand Down Expand Up @@ -408,8 +412,7 @@ class TypeComparer(initctx: Context) extends DotClass {
val base = tp1.baseTypeRef(cls2)
if (base.exists && (base ne tp1)) return isSubType(base, tp2)
if ( cls2 == defn.SingletonClass && tp1.isStable
|| cls2 == defn.NotNullClass && tp1.isNotNull
|| (defn.hkTraits contains cls2) && isSubTypeHK(tp1, tp2)) return true
|| cls2 == defn.NotNullClass && tp1.isNotNull) return true
}
fourthTry(tp1, tp2)
}
Expand All @@ -426,7 +429,9 @@ class TypeComparer(initctx: Context) extends DotClass {
}
case _ => tp2
}
def compareRefined: Boolean = tp1.widen match {
def compareRefined: Boolean =
if (defn.hkTraits contains parent2.typeSymbol) isSubTypeHK(tp1, tp2)
else tp1.widen match {
case tp1 @ RefinedType(parent1, name1) if nameMatches(name1, name2, tp1, tp2) =>
// optimized case; all info on tp1.name2 is in refinement tp1.refinedInfo.
isSubType(tp1.refinedInfo, tp2.refinedInfo) && {
Expand All @@ -439,7 +444,7 @@ class TypeComparer(initctx: Context) extends DotClass {
case mbr: SingleDenotation => qualifies(mbr)
case _ => mbr hasAltWith qualifies
}
def hasMatchingMember(name: Name): Boolean = /*>|>*/ ctx.traceIndented(s"hasMatchingMember($name) ${tp1.member(name)}", subtyping) /*<|<*/ (
def hasMatchingMember(name: Name): Boolean = /*>|>*/ ctx.traceIndented(s"hasMatchingMember($name) ${tp1.member(name).info.show}", subtyping) /*<|<*/ (
memberMatches(tp1 member name)
||
{ // special case for situations like:
Expand Down Expand Up @@ -467,7 +472,7 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2 @ MethodType(_, formals2) =>
def compareMethod = tp1 match {
case tp1 @ MethodType(_, formals1) =>
tp1.signature == tp2.signature &&
(tp1.signature sameParams tp2.signature) &&
(if (Config.newMatch) subsumeParams(formals1, formals2, tp1.isJava, tp2.isJava)
else matchingParams(formals1, formals2, tp1.isJava, tp2.isJava)) &&
tp1.isImplicit == tp2.isImplicit && // needed?
Expand Down Expand Up @@ -532,7 +537,20 @@ class TypeComparer(initctx: Context) extends DotClass {
(tp1.symbol eq NullClass) && tp2.dealias.typeSymbol.isNullableClass
}
case tp1: SingletonType =>
isNewSubType(tp1.underlying.widenExpr, tp2)
isNewSubType(tp1.underlying.widenExpr, tp2) || {
// if tp2 == p.type and p: q.type then try tp1 <:< q.type as a last effort.
tp2 match {
case tp2: TermRef =>
tp2.info match {
case tp2i: TermRef =>
isSubType(tp1, tp2i)
case _ =>
false
}
case _ =>
false
}
}
case tp1: RefinedType =>
isNewSubType(tp1.parent, tp2)
case AndType(tp11, tp12) =>
Expand Down Expand Up @@ -612,20 +630,33 @@ class TypeComparer(initctx: Context) extends DotClass {
* This is the case if `tp1` and `tp2` have the same number
* of type parameters, the bounds of tp1's paremeters
* are contained in the corresponding bounds of tp2's parameters
* and the variances of correesponding parameters agree.
* and the variances of the parameters agree.
* The variances agree if the supertype parameter is invariant,
* or both parameters have the same variance.
*
* Note: When we get to isSubTypeHK, it might be that tp1 is
* instantiated, or not. If it is instantiated, we compare
* actual argument infos against higher-kinded bounds,
* if it is not instantiated we compare type parameter bounds
* and also compare variances.
*/
def isSubTypeHK(tp1: Type, tp2: Type): Boolean = {
def isSubTypeHK(tp1: Type, tp2: Type): Boolean = ctx.traceIndented(s"isSubTypeHK(${tp1.show}, ${tp2.show}", subtyping) {
val tparams = tp1.typeParams
val hkArgs = tp2.argInfos
(hkArgs.length == tparams.length) && {
val base = tp1.narrow
(tparams, hkArgs).zipped.forall { (tparam, hkArg) =>
isSubType(base.memberInfo(tparam), hkArg.bounds) // TODO: base.memberInfo needed?
} &&
(tparams, tp2.typeSymbol.typeParams).zipped.forall { (tparam, tparam2) =>
tparam.variance == tparam2.variance
}
}
val argInfos1 = tp1.argInfos
val args1 =
if (argInfos1.nonEmpty) argInfos1 // tp1 is instantiated, use the argument infos
else { // tp1 is uninstantiated, use the parameter bounds
val base = tp1.narrow
tparams.map(base.memberInfo)
}
val hkBounds = tp2.argInfos.map(_.asInstanceOf[TypeBounds])
val boundsOK = (hkBounds corresponds args1)(_ contains _)
val variancesOK =
argInfos1.nonEmpty || (tparams corresponds tp2.typeSymbol.name.hkVariances) { (tparam, v) =>
v == 0 || tparam.variance == v
}
hk.println(s"isSubTypeHK: args1 = $args1, hk-bounds = $hkBounds $boundsOK $variancesOK")
boundsOK && variancesOK
}

def trySetType(tr: NamedType, bounds: TypeBounds): Boolean =
Expand Down
Loading