summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2010-09-16 22:26:04 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2010-09-16 22:26:04 +0000
commitce223fe7abc47af712382a64404604e75f9f4d20 (patch)
tree2af8639c5c9d9bcda88ef59b4598b2b4d5221406 /src/compiler/scala/tools
parent44784f3e41c2cc141c3eb5a0dcb656005befcfa4 (diff)
downloadscala-ce223fe7abc47af712382a64404604e75f9f4d20.tar.gz
scala-ce223fe7abc47af712382a64404604e75f9f4d20.tar.bz2
scala-ce223fe7abc47af712382a64404604e75f9f4d20.zip
closes #1569, #3731: refactored dependent metho...
closes #1569, #3731: refactored dependent method types to get rid of debruijn indices and use singleton types instead. this is the core of the dependent types refactoring, no implicit or inference changes (one baffling discovery: resultType should drop annotations that don't subclass TypeConstraint, even in the trivial case... wow -- thanks to Tiark for helping me figure it out on a terrace in Barcelona TODO: probably need a more principled approach to the propagation of plugin type-annotations) review by odersky
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala10
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala11
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala23
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Scopes.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala207
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala16
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala111
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/util/ShowPickled.scala2
16 files changed, 251 insertions, 179 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index a9300ff304..de48ff9931 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -29,6 +29,16 @@ trait CompilationUnits { self: Global =>
/** all comments found in this compilation unit */
val comments = new ListBuffer[Comment]
+// def parseSettings() = {
+// val argsmarker = "SCALAC_ARGS"
+// if(comments nonEmpty) {
+// val pragmas = comments find (_.text.startsWith("//#")) // only parse first one
+// pragmas foreach { p =>
+// val i = p.text.indexOf(argsmarker)
+// if(i > 0)
+// }
+// }
+// }
/** Note: depends now contains toplevel classes.
* To get their sourcefiles, you need to dereference with .sourcefile
*/
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 3eb7193530..75dd7aea63 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -519,10 +519,12 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
phasesSet += analyzer.namerFactory // note: types are there because otherwise
phasesSet += analyzer.packageObjects // consistency check after refchecks would fail.
phasesSet += analyzer.typerFactory
- phasesSet += superAccessors // add super accessors
- phasesSet += pickler // serialize symbol tables
- phasesSet += refchecks // perform reference and override checking, translate nested objects
- // phasesSet += devirtualize // Desugar virtual classes
+ phasesSet += superAccessors // add super accessors
+ phasesSet += pickler // serialize symbol tables
+ phasesSet += refchecks // perform reference and override checking, translate nested objects
+
+// if (false && settings.YvirtClasses)
+// phasesSet += devirtualize // Desugar virtual classes4
phasesSet += uncurry // uncurry, translate function values to anonymous classes
phasesSet += tailCalls // replace tail calls by jumps
@@ -693,6 +695,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
/** add unit to be compiled in this run */
private def addUnit(unit: CompilationUnit) {
+// unit.parseSettings()
unitbuf += unit
compiledFiles += unit.source.file.path
}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 41e93ae386..f43a1a6ae3 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -118,17 +118,20 @@ abstract class TreeGen {
else mkAttributedIdent(sym)
/** Replaces tree type with a stable type if possible */
- def stabilize(tree: Tree): Tree = tree match {
- case Ident(_) =>
- if (tree.symbol.isStable) tree.setType(singleType(tree.symbol.owner.thisType, tree.symbol))
- else tree
- case Select(qual, _) =>
- assert((tree.symbol ne null) && (qual.tpe ne null))
- if (tree.symbol.isStable && qual.tpe.isStable)
- tree.setType(singleType(qual.tpe, tree.symbol))
- else tree
+ def stabilize(tree: Tree): Tree = {
+ for(tp <- stableTypeFor(tree)) tree.tpe = tp
+ tree
+ }
+
+ /** Computes stable type for a tree if possible */
+ def stableTypeFor(tree: Tree): Option[Type] = tree match {
+ case Ident(_) if tree.symbol.isStable =>
+ Some(singleType(tree.symbol.owner.thisType, tree.symbol))
+ case Select(qual, _) if {assert((tree.symbol ne null) && (qual.tpe ne null));
+ tree.symbol.isStable && qual.tpe.isStable} =>
+ Some(singleType(qual.tpe, tree.symbol))
case _ =>
- tree
+ None
}
/** Cast `tree' to type `pt' */
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 131b0d0a03..61d45114a9 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1794,7 +1794,7 @@ self =>
val name = ident()
var bynamemod = 0
val tpt =
- if (settings.Xexperimental.value && !owner.isTypeName && in.token != COLON) {
+ if (settings.YmethodInfer.value && !owner.isTypeName && in.token != COLON) {
TypeTree()
} else { // XX-METHOD-INFER
accept(COLON)
@@ -2344,7 +2344,7 @@ self =>
else (accessModifierOpt(), paramClauses(name, classContextBounds, mods.hasFlag(Flags.CASE)))
var mods1 = mods
if (mods hasFlag Flags.TRAIT) {
- if (settings.Xexperimental.value && in.token == SUBTYPE) mods1 |= Flags.DEFERRED
+ if (settings.YvirtClasses && in.token == SUBTYPE) mods1 |= Flags.DEFERRED
} else if (in.token == SUBTYPE) {
syntaxError("classes are not allowed to be virtual", false)
}
@@ -2435,7 +2435,7 @@ self =>
def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers,
vparamss: List[List[ValDef]], tstart: Int): Template = {
val (parents0, argss, self, body) =
- if (in.token == EXTENDS || settings.Xexperimental.value && (mods hasFlag Flags.TRAIT) && in.token == SUBTYPE) {
+ if (in.token == EXTENDS || settings.YvirtClasses && (mods hasFlag Flags.TRAIT) && in.token == SUBTYPE) {
in.nextToken()
template(mods hasFlag Flags.TRAIT)
} else if ((in.token == SUBTYPE) && (mods hasFlag Flags.TRAIT)) {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 01f1d2c211..b175cb24ee 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -55,7 +55,6 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions and assumptions")
val elidebelow = IntSetting ("-Xelide-below", "Generate calls to @elidable-marked methods only if method priority is greater than argument.",
elidable.ASSERTION, None, elidable.byName.get(_))
- val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes")
val future = BooleanSetting ("-Xfuture", "Turn on future language features")
val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot", "")
@@ -79,10 +78,18 @@ trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
val Xshowobj = StringSetting ("-Xshow-object", "object", "Show object info", "")
val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases")
val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files", "scala.tools.nsc.io.SourceReader")
+
val Xwarnfatal = BooleanSetting ("-Xfatal-warnings", "Fail the compilation if there are any warnings.")
val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
+ // Experimental Extensions
+ val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions") .
+ withPostSetHook(_ => List(YdepMethTpes, YmethodInfer) foreach (_.value = true)) //YvirtClasses,
+ val YdepMethTpes = BooleanSetting ("-Ydependent-method-types", "Allow dependent method types")
+ val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods")
+ val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
+
/** Compatibility stubs for options whose value name did
* not previously match the option name.
*/
diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
index bc8b93ac2c..b5e23d61f0 100644
--- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala
@@ -217,7 +217,7 @@ trait Scopes {
if (e eq null) NoSymbol else e.sym
}
- /** Returns an iterator eidling every symbol with given name in this scope.
+ /** Returns an iterator yielding every symbol with given name in this scope.
*/
def lookupAll(name: Name): Iterator[Symbol] = new Iterator[Symbol] {
var e = lookupEntry(name)
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index b3d2c56285..f17b33aa5a 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -264,9 +264,17 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
/** Is this type a structural refinement type (it 'refines' members that have not been inherited) */
def isStructuralRefinement: Boolean = false
+ /** Does this type depend immediately on an enclosing method parameter?
+ * i.e., is it a singleton type whose termSymbol refers to an argument of the symbol's owner (which is a method)
+ */
+ def isImmediatelyDependent: Boolean = false
+
/** Does this depend on an enclosing method parameter? */
def isDependent: Boolean = IsDependentCollector.collect(this)
+ /** True for WildcardType or BoundedWildcardType */
+ def isWildcard = false
+
/** The term symbol associated with the type
* Note that the symbol of the normalized type is returned (@see normalize)
*/
@@ -355,7 +363,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
*/
def remove(clazz: Symbol): Type = this
- def resultApprox: Type = ApproximateDeBruijnMap(resultType)
+ def resultApprox: Type = ApproximateDependentMap(resultType)
/** For a curried method or poly type its non-method result type,
* the type itself for all other types */
@@ -1012,12 +1020,14 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
/** An object representing an unknown type */
case object WildcardType extends Type {
+ override def isWildcard = true
override def safeToString: String = "?"
// override def isNullable: Boolean = true
override def kind = "WildcardType"
}
case class BoundedWildcardType(override val bounds: TypeBounds) extends Type {
+ override def isWildcard = true
override def safeToString: String = "?" + bounds
override def kind = "BoundedWildcardType"
}
@@ -1071,13 +1081,13 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
else sym.tpe
}
- case class DeBruijnIndex(level: Int, paramId: Int) extends Type {
- override def isTrivial = true
- override def isStable = true
- override def safeToString = "<param "+level+"."+paramId+">"
- override def kind = "DeBruijnIndex"
- // todo: this should be a subtype, which forwards to underlying
- }
+ // case class DeBruijnIndex(level: Int, paramId: Int) extends Type {
+ // override def isTrivial = true
+ // override def isStable = true
+ // override def safeToString = "<param "+level+"."+paramId+">"
+ // override def kind = "DeBruijnIndex"
+ // // todo: this should be a subtype, which forwards to underlying
+ // }
/** A class for singleton types of the form &lt;prefix&gt;.&lt;sym.name&gt;.type.
* Cannot be created directly; one should always use
@@ -1101,6 +1111,9 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
underlyingCache
}
+ // more precise conceptually, but causes cyclic errors: (paramss exists (_ contains sym))
+ override def isImmediatelyDependent = (sym ne NoSymbol) && (sym.owner.isMethod && sym.isValueParameter)
+
override def isVolatile : Boolean = underlying.isVolatile && (!sym.isStable)
/*
override def narrow: Type = {
@@ -1190,9 +1203,8 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
case tv: TypeVar => tvs += tv
case _ =>
}
- val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap
- val paramToVarMap = varToParamMap map (_.swap)
-
+ val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap
+ val paramToVarMap = varToParamMap map (_.swap)
val varToParam = new TypeMap {
def apply(tp: Type) = varToParamMap get tp match {
case Some(sym) => sym.tpe
@@ -1559,7 +1571,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
* Cannot be created directly; one should always use `typeRef'
* for creation. (@M: Otherwise hashing breaks)
*
- * @M: Higher-kinded types are represented as TypeRefs with a symbol that has type parameters, but with args==List()
+ * @M: a higher-kinded type is represented as a TypeRef with sym.info.typeParams.nonEmpty, but args.isEmpty
* @param pre ...
* @param sym ...
* @param args ...
@@ -1750,8 +1762,7 @@ A type's typeSymbol should never be inspected directly.
// TODO: this would not be necessary if we could replace the call to sym.unsafeTypeParams in typeParamsDirect
// by a call to sym.typeParams, but need to verify that that does not lead to spurious "illegal cycle" errors
// the need for refreshing the cache is illustrated by #2278
- // TODO: no test case in the suite because don't know how to tell partest to compile in different runs,
- // and in a specific order
+ // TODO: test case that is compiled in a specific order and in different runs
private var normalizeTyparCount = -1
override def normalize: Type = {
@@ -1887,8 +1898,11 @@ A type's typeSymbol should never be inspected directly.
*/
case class MethodType(override val params: List[Symbol],
override val resultType: Type) extends Type {
- override val isTrivial: Boolean =
- params.forall(_.tpe.isTrivial) && resultType.isTrivial
+ override def isTrivial: Boolean = isTrivial0
+ private lazy val isTrivial0 =
+ resultType.isTrivial && params.forall{p => p.tpe.isTrivial && (
+ !settings.YdepMethTpes.value || !(params.exists(_.tpe.contains(p)) || resultType.contains(p)))
+ }
def isImplicit = params.nonEmpty && params.head.isImplicit
def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized?
@@ -1902,30 +1916,36 @@ A type's typeSymbol should never be inspected directly.
override def boundSyms = params ::: resultType.boundSyms
- override def resultType(actuals: List[Type]) = {
- val map = new InstantiateDeBruijnMap(actuals)
- val rawResTpe = map.apply(resultType)
-
- if (phase.erasedTypes)
- rawResTpe
- else
- existentialAbstraction(map.existentialsNeeded, rawResTpe)
+ // this is needed for plugins to work correctly, only TypeConstraint annotations are supposed to be carried over
+ // TODO: this should probably be handled in a more structured way in adapt -- remove this map in resultType and watch the continuations tests fail
+ object dropNonContraintAnnotations extends TypeMap {
+ override val dropNonConstraintAnnotations = true
+ def apply(x: Type) = mapOver(x)
}
- override def finalResultType: Type = resultType.finalResultType
-
- private def dependentToString(base: Int): String = {
- val params = for ((pt, n) <- paramTypes.zipWithIndex) yield "x$"+n+":"+pt
- val res = resultType match {
- case mt: MethodType => mt.dependentToString(base + params.length)
- case rt => rt.toString
+ override def resultType(actuals: List[Type]) =
+ if(isTrivial) dropNonContraintAnnotations(resultType)
+ else {
+ if(actuals.length == params.length) {
+ val idm = new InstantiateDependentMap(params, actuals)
+ val res = idm(resultType)
+ // println("resultTypeDep "+(params, actuals, resultType, idm.existentialsNeeded, "\n= "+ res))
+ existentialAbstraction(idm.existentialsNeeded, res)
+ } else {
+ // Thread.dumpStack()
+ // println("resultType "+(params, actuals, resultType))
+ if (phase.erasedTypes) resultType
+ else existentialAbstraction(params, resultType)
+ }
}
- params.mkString("(", ",", ")")+res
- }
+
+ // implicit args can only be depended on in result type: TODO this may be generalised so that the only constraint is dependencies are acyclic
+ def approximate: MethodType = MethodType(params, resultApprox)
+
+ override def finalResultType: Type = resultType.finalResultType
override def safeToString: String =
- if (resultType.isDependent) dependentToString(0)
- else params.map(_.defString).mkString("(", ",", ")") + resultType
+ params.map(_.defString).mkString("(", ",", ")") + resultType
override def cloneInfo(owner: Symbol) = {
val vparams = cloneSymbols(params, owner)
@@ -2147,7 +2167,7 @@ A type's typeSymbol should never be inspected directly.
object TypeVar {
def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List())
- def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams)
+ def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) // TODO why not initialise TypeConstraint with bounds of tparam?
def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = new TypeVar(origin, constr, args, params)
}
@@ -2850,7 +2870,7 @@ A type's typeSymbol should never be inspected directly.
if ((tparams1 eq tparams) && (result1 eq result)) tp
else PolyType(tparams1, result1.substSym(tparams, tparams1))
case ConstantType(_) => tp
- case DeBruijnIndex(_, _) => tp
+ // case DeBruijnIndex(_, _) => tp
case SuperType(thistp, supertp) =>
val thistp1 = this(thistp)
val supertp1 = this(supertp)
@@ -3227,7 +3247,7 @@ A type's typeSymbol should never be inspected directly.
else if (matches(from.head, sym)) toType(tp, to.head)
else subst(tp, sym, from.tail, to.tail)
- private def renameBoundSyms(tp: Type): Type = tp match {
+ protected def renameBoundSyms(tp: Type): Type = tp match {
case MethodType(ps, restp) =>
val ps1 = cloneSymbols(ps)
copyMethodType(tp, ps1, renameBoundSyms(restp.substSym(ps, ps1)))
@@ -3374,11 +3394,35 @@ A type's typeSymbol should never be inspected directly.
}
}
+// dependent method types
+ object IsDependentCollector extends TypeCollector(false) {
+ def traverse(tp: Type) {
+ if(tp isImmediatelyDependent) result = true
+ else if (!result) mapOver(tp)
+ }
+ }
+
+ object ApproximateDependentMap extends TypeMap {
+ def apply(tp: Type): Type =
+ if(tp isImmediatelyDependent) WildcardType
+ else mapOver(tp)
+ }
+
+/*
/** Most of the implementation for MethodType.resultType. The
* caller also needs to existentially quantify over the
* variables in existentialsNeeded.
*/
class InstantiateDeBruijnMap(actuals: List[Type]) extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case DeBruijnIndex(level, pid) =>
+ if (level == 1)
+ if (pid < actuals.length) actuals(pid) else tp
+ else DeBruijnIndex(level - 1, pid)
+ case _ =>
+ mapOver(tp)
+ }
+
override val dropNonConstraintAnnotations = true
private var existSyms = immutable.Map.empty[Int, Symbol]
@@ -3401,15 +3445,6 @@ A type's typeSymbol should never be inspected directly.
sym
}
- def apply(tp: Type): Type = tp match {
- case DeBruijnIndex(level, pid) =>
- if (level == 1)
- if (pid < actuals.length) actuals(pid) else tp
- else DeBruijnIndex(level - 1, pid)
- case _ =>
- mapOver(tp)
- }
-
override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = {
object treeTrans extends TypeMapTransformer {
override def transform(tree: Tree): Tree =
@@ -3442,16 +3477,71 @@ A type's typeSymbol should never be inspected directly.
treeTrans.transform(arg)
}
}
+*/
- object ApproximateDeBruijnMap extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case DeBruijnIndex(level, pid) =>
- WildcardType
- case _ =>
- mapOver(tp)
+ class InstantiateDependentMap(params: List[Symbol], actuals: List[Type]) extends SubstTypeMap(params, actuals) {
+ override protected def renameBoundSyms(tp: Type): Type = tp match {
+ case MethodType(ps, restp) => tp // the whole point of this substitution is to instantiate these args
+ case _ => super.renameBoundSyms(tp)
+ }
+ // TODO: should we optimise this? only need to consider singletontypes
+
+ override val dropNonConstraintAnnotations = true
+
+ def existentialsNeeded: List[Symbol] = existSyms.filter(_ ne null).toList
+
+ private val existSyms: Array[Symbol] = new Array(actuals.length)
+ private def haveExistential(i: Int) = {assert((i >= 0) && (i <= actuals.length)); existSyms(i) ne null}
+
+ /* Return the type symbol for referencing a parameter inside the existential quantifier.
+ * (Only needed if the actual is unstable.)
+ */
+ def existSymFor(actualIdx: Int) =
+ if (haveExistential(actualIdx)) existSyms(actualIdx)
+ else {
+ val oldSym = params(actualIdx)
+ val symowner = oldSym.owner
+ val bound = singletonBounds(actuals(actualIdx))
+
+ val sym = symowner.newExistential(oldSym.pos, oldSym.name+".type")
+ sym.setInfo(bound)
+ sym.setFlag(oldSym.flags)
+
+ existSyms(actualIdx) = sym
+ sym
+ }
+
+ //AM propagate more info to annotations -- this seems a bit ad-hoc... (based on code by spoon)
+ override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = {
+ object treeTrans extends Transformer {
+ override def transform(tree: Tree): Tree = {
+ tree match {
+ case RefParamAt(pid) =>
+ if(actuals(pid) isStable) mkAttributedQualifier(actuals(pid), tree.symbol)
+ else {
+ val sym = existSymFor(pid)
+ (Ident(sym.name)
+ copyAttrs tree
+ setType typeRef(NoPrefix, sym, Nil))
+ }
+ case _ => super.transform(tree)
+ }
+ }
+ object RefParamAt {
+ def unapply(tree: Tree): Option[(Int)] = tree match {
+ case Ident(_) =>
+ val pid = params indexOf tree.symbol
+ if(pid != -1) Some((pid)) else None
+ case _ => None
+ }
+ }
+ }
+
+ treeTrans.transform(arg)
}
}
+
object StripAnnotationsMap extends TypeMap {
def apply(tp: Type): Type = tp match {
case AnnotatedType(_, atp, _) =>
@@ -3556,15 +3646,6 @@ A type's typeSymbol should never be inspected directly.
}
}
- object IsDependentCollector extends TypeCollector(false) {
- def traverse(tp: Type) {
- tp match {
- case DeBruijnIndex(_, _) => result = true
- case _ => if (!result) mapOver(tp)
- }
- }
- }
-
/** A map to compute the most deeply nested owner that contains all the symbols
* of thistype or prefixless typerefs/singletype occurrences in given type.
*/
@@ -4055,7 +4136,7 @@ A type's typeSymbol should never be inspected directly.
case mt1: MethodType =>
tp2 match {
case mt2: MethodType =>
- // new dependent types: probably fix this, use substSym as done for PolyType
+ // DEPMETTODO new dependent types: probably fix this, use substSym as done for PolyType
return isSameTypes(mt1.paramTypes, mt2.paramTypes) &&
mt1.resultType =:= mt2.resultType &&
mt1.isImplicit == mt2.isImplicit
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 91141ce4d6..e3bd67ec81 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -164,7 +164,7 @@ abstract class Pickler extends SubComponent {
*/
private def putType(tp: Type): Unit = if (putEntry(tp)) {
tp match {
- case NoType | NoPrefix | DeBruijnIndex(_, _) =>
+ case NoType | NoPrefix /*| DeBruijnIndex(_, _) */ =>
;
case ThisType(sym) =>
putSymbol(sym)
@@ -592,8 +592,8 @@ abstract class Pickler extends SubComponent {
writeRef(restpe); writeRefs(tparams); POLYtpe
case ExistentialType(tparams, restpe) =>
writeRef(restpe); writeRefs(tparams); EXISTENTIALtpe
- case DeBruijnIndex(l, i) =>
- writeNat(l); writeNat(i); DEBRUIJNINDEXtpe
+ // case DeBruijnIndex(l, i) =>
+ // writeNat(l); writeNat(i); DEBRUIJNINDEXtpe
case c @ Constant(_) =>
if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0)
else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue)
@@ -1042,8 +1042,8 @@ abstract class Pickler extends SubComponent {
case ExistentialType(tparams, restpe) =>
print("EXISTENTIALtpe "); printRef(restpe); printRefs(tparams);
print("||| "+entry)
- case DeBruijnIndex(l, i) =>
- print("DEBRUIJNINDEXtpe "); print(l+" "+i)
+ // case DeBruijnIndex(l, i) =>
+ // print("DEBRUIJNINDEXtpe "); print(l+" "+i)
case c @ Constant(_) =>
print("LITERAL ")
if (c.tag == BooleanTag) print("Boolean "+(if (c.booleanValue) 1 else 0))
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index a94838e163..05ffc6c7b7 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -30,14 +30,14 @@ abstract class UnPickler extends reflect.generic.UnPickler {
protected override def debug = settings.debug.value
- override def noSuchTypeTag(tag: Int, end: Int): Type = {
- tag match {
- case DEBRUIJNINDEXtpe =>
- DeBruijnIndex(readNat(), readNat())
- case _ =>
- super.noSuchTypeTag(tag, end)
- }
- }
+ // override def noSuchTypeTag(tag: Int, end: Int): Type = {
+ // tag match {
+ // case DEBRUIJNINDEXtpe =>
+ // DeBruijnIndex(readNat(), readNat())
+ // case _ =>
+ // super.noSuchTypeTag(tag, end)
+ // }
+ // }
override protected def errorMissingRequirement(name: Name, owner: Symbol) =
errorMissingRequirement(
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 814434d46c..635a1983e2 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -165,8 +165,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast.
cloneSymbols(params) map (p => p.setInfo(apply(p.tpe))),
if (restpe.typeSymbol == UnitClass)
erasedTypeRef(UnitClass)
- else if (settings.Xexperimental.value)
- apply(mt.resultType(params map (_.tpe))) // this gets rid of DeBruijnTypes
+ else if (settings.YdepMethTpes.value)
+ // this replaces each typeref that refers to an argument by the type `p.tpe` of the actual argument p (p in params)
+ apply(mt.resultType(params map (_.tpe)))
else
apply(restpe))
case RefinedType(parents, decls) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 0c81bb3887..687f7cae4b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -30,11 +30,6 @@ trait Infer {
def isVarArgs(params: List[Symbol]) = !params.isEmpty && isRepeatedParamType(params.last.tpe)
def isVarArgTpes(formals: List[Type]) = !formals.isEmpty && isRepeatedParamType(formals.last)
- def isWildcard(tp: Type) = tp match {
- case WildcardType | BoundedWildcardType(_) => true
- case _ => false
- }
-
/** The formal parameter types corresponding to <code>formals</code>.
* If <code>formals</code> has a repeated last parameter, a list of
* (nargs - params.length + 1) copies of its type is returned.
@@ -566,7 +561,7 @@ trait Infer {
(tparams, targs).zipped.map{ (tparam, targ) =>
if (targ.typeSymbol == NothingClass &&
- (isWildcard(restpe) || notCovariantIn(tparam, restpe))) {
+ (restpe.isWildcard || notCovariantIn(tparam, restpe))) {
tparam -> None
} else {
tparam -> Some(
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index b5d3a939e1..262a760958 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -767,99 +767,68 @@ trait Namers { self: Analyzer =>
val tparamSyms = typer.reenterTypeParams(tparams)
// since the skolemized tparams are in scope, the TypeRefs in vparamSymss refer to skolemized tparams
var vparamSymss = enterValueParams(meth, vparamss)
+ // DEPMETTODO: do we need to skolemize value parameter symbols?
if (tpt.isEmpty && meth.name == nme.CONSTRUCTOR) {
tpt defineType context.enclClass.owner.tpe
tpt setPos meth.pos.focus
}
- def convertToDeBruijn(vparams: List[Symbol], level: Int): TypeMap = new TypeMap {
- def debruijnFor(param: Symbol) =
- DeBruijnIndex(level, vparams indexOf param)
- def apply(tp: Type) = {
- tp match {
- case SingleType(_, sym) =>
- if (settings.Xexperimental.value && sym.owner == meth && (vparams contains sym)) {
-/*
- if (sym hasFlag IMPLICIT) {
- context.error(sym.pos, "illegal type dependence on implicit parameter")
- ErrorType
- } else
-*/
- debruijnFor(sym)
- } else tp
- case MethodType(params, restpe) =>
- val params1 = this.mapOver(params)
- val restpe1 = convertToDeBruijn(vparams, level + 1)(restpe)
- if ((params1 eq params) && (restpe1 eq restpe)) tp
- else copyMethodType(tp, params1, restpe1)
- case _ =>
- mapOver(tp)
- }
- }
-
- // AnnotatedTypes can contain trees in the annotation arguments. When accessing a
- // parameter in an annotation, set the type of the Ident to the DeBruijnIndex
- object treeTrans extends TypeMapTransformer {
- override def transform(tree: Tree): Tree =
- tree match {
- case Ident(name) if (vparams contains tree.symbol) =>
- val dtpe = debruijnFor(tree.symbol)
- val dsym =
- context.owner.newLocalDummy(tree.symbol.pos)
- .newValue(tree.symbol.pos, name)
-
- dsym.setFlag(PARAM)
- dsym.setInfo(dtpe)
- Ident(name).setSymbol(dsym).copyAttrs(tree).setType(dtpe)
- case tree => super.transform(tree)
- }
- }
-
- // for type annotations (which may contain trees)
- override def mapOver(arg: Tree) = Some(treeTrans.transform(arg))
- }
-
- val checkDependencies: TypeTraverser = new TypeTraverser {
- def traverse(tp: Type) = {
- tp match {
- case SingleType(_, sym) =>
- if (sym.owner == meth && (vparamSymss exists (_ contains sym)))
- context.error(
- sym.pos,
- "illegal dependent method type"+
- (if (settings.Xexperimental.value)
- ": parameter appears in the type of another parameter in the same section or an earlier one"
- else ""))
- case _ =>
- mapOver(tp)
- }
- this
- }
- }
/** Called for all value parameter lists, right to left
* @param vparams the symbols of one parameter list
* @param restpe the result type (possibly a MethodType)
*/
def makeMethodType(vparams: List[Symbol], restpe: Type) = {
+ // TODODEPMET: check that we actually don't need to do anything here
// new dependent method types: probably OK already, since 'enterValueParams' above
// enters them in scope, and all have a lazy type. so they may depend on other params. but: need to
// check that params only depend on ones in earlier sections, not the same. (done by checkDependencies,
// so re-use / adapt that)
val params = vparams map (vparam =>
if (meth hasFlag JAVA) vparam.setInfo(objToAny(vparam.tpe)) else vparam)
- val restpe1 = convertToDeBruijn(vparams, 1)(restpe) // new dependent types: replace symbols in restpe with the ones in vparams
- if (meth hasFlag JAVA) JavaMethodType(params, restpe1)
- else MethodType(params, restpe1)
+ // TODODEPMET necessary?? new dependent types: replace symbols in restpe with the ones in vparams
+ if (meth hasFlag JAVA) JavaMethodType(params, restpe)
+ else MethodType(params, restpe)
}
- def thisMethodType(restpe: Type) =
+ def thisMethodType(restpe: Type) = {
+ import scala.collection.mutable.ListBuffer
+ val okParams = ListBuffer[Symbol]()
+ // can we relax these restrictions? see test/files/pos/depmet_implicit_oopsla_session_2.scala and neg/depmet_try_implicit.scala for motivation
+ // should allow forward references since type selections on implicit args are like type parameters:
+ // def foo[T](a: T, x: w.T2)(implicit w: ComputeT2[T])
+ // is more compact than: def foo[T, T2](a: T, x: T2)(implicit w: ComputeT2[T, T2])
+ // moreover, the latter is not an encoding of the former, which hides type inference of T2, so you can specify T while T2 is purely computed
+ val checkDependencies: TypeTraverser = new TypeTraverser {
+ def traverse(tp: Type) = {
+ tp match {
+ case SingleType(_, sym) =>
+ if (sym.owner == meth && sym.isValueParameter && !(okParams contains sym))
+ context.error(
+ sym.pos,
+ "illegal dependent method type"+
+ (if (settings.YdepMethTpes.value)
+ ": parameter appears in the type of another parameter in the same section or an earlier one"
+ else ""))
+ case _ =>
+ mapOver(tp)
+ }
+ this
+ }
+ }
+ for(vps <- vparamSymss) {
+ for(p <- vps) checkDependencies(p.info)
+ if(settings.YdepMethTpes.value) okParams ++= vps // can only refer to symbols in earlier parameter sections (if the extension is enabled)
+ }
+ checkDependencies(restpe) // DEPMETTODO: check not needed when they become on by default
+
polyType(
- tparamSyms, // deSkolemized symbols
- if (vparamSymss.isEmpty) PolyType(List(), restpe)
+ tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args?
+ if (vparamSymss.isEmpty) PolyType(List(), restpe) // nullary method type
// vparamss refer (if they do) to skolemized tparams
- else checkDependencies((vparamSymss :\ restpe) (makeMethodType)))
+ else (vparamSymss :\ restpe) (makeMethodType))
+ }
var resultPt = if (tpt.isEmpty) WildcardType else typer.typedType(tpt).tpe
val site = meth.owner.thisType
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 162749da41..5c90a69c94 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -683,7 +683,7 @@ abstract class RefChecks extends InfoTransform {
case NoPrefix => ;
case ThisType(_) => ;
case ConstantType(_) => ;
- case DeBruijnIndex(_, _) => ;
+ // case DeBruijnIndex(_, _) => ;
case SingleType(pre, sym) =>
validateVariance(pre, variance)
case TypeRef(pre, sym, args) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 1166f62ddb..be576289f6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -139,7 +139,7 @@ trait TypeDiagnostics {
def applyErrorMsg(tree: Tree, msg: String, argtpes: List[Type], pt: Type) = {
def asParams(xs: List[Any]) = xs.mkString("(", ", ", ")")
- def resType = if (isWildcard(pt)) "" else " with expected result type " + pt
+ def resType = if (pt isWildcard) "" else " with expected result type " + pt
def allTypes = (alternatives(tree) flatMap (_.paramTypes)) ++ argtpes :+ pt
withDisambiguation(allTypes: _*) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7ef494ea73..e71ad5475c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1751,7 +1751,7 @@ trait Typers { self: Analyzer =>
error(vparam1.pos, "*-parameter must come last")
var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt))
- if (!settings.Xexperimental.value) {
+ if (!settings.YdepMethTpes.value) {
for (vparams <- vparamss1; vparam <- vparams) {
checkNoEscaping.locals(context.scope, WildcardType, vparam.tpt); ()
}
@@ -2420,7 +2420,10 @@ trait Typers { self: Analyzer =>
val tparams = context.extractUndetparams()
if (tparams.isEmpty) { // all type params are defined
val args1 = typedArgs(args, argMode(fun, mode), paramTypes, formals)
- val restpe = mt.resultType(args1 map (_.tpe)) // instantiate dependent method types
+ // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
+ // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
+ // precise(foo) : foo.type => foo.type
+ val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
def ifPatternSkipFormals(tp: Type) = tp match {
case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp
case _ => tp
diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
index 82911892d9..458116845d 100644
--- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala
+++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala
@@ -96,7 +96,7 @@ object ShowPickled extends Names {
case ANNOTATEDtpe => "ANNOTATEDtpe"
case ANNOTINFO => "ANNOTINFO"
case ANNOTARGARRAY => "ANNOTARGARRAY"
- case DEBRUIJNINDEXtpe => "DEBRUIJNINDEXtpe"
+ // case DEBRUIJNINDEXtpe => "DEBRUIJNINDEXtpe"
case EXISTENTIALtpe => "EXISTENTIALtpe"
case TREE => "TREE"
case MODIFIERS => "MODIFIERS"