summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--test/files/neg/depmet_1.check10
-rw-r--r--test/files/neg/depmet_1.flags1
-rw-r--r--test/files/neg/depmet_1.scala5
-rw-r--r--test/files/pos/depmet_1.flags1
-rw-r--r--test/files/pos/depmet_1.scala6
-rw-r--r--test/files/pos/t1569.flags1
-rw-r--r--test/files/pos/t1569.scala5
-rw-r--r--test/files/run/constrained-types.check4
-rw-r--r--test/files/run/constrained-types.scala2
25 files changed, 283 insertions, 182 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"
diff --git a/test/files/neg/depmet_1.check b/test/files/neg/depmet_1.check
new file mode 100644
index 0000000000..7a4f845fd5
--- /dev/null
+++ b/test/files/neg/depmet_1.check
@@ -0,0 +1,10 @@
+depmet_1.scala:2: error: illegal dependent method type: parameter appears in the type of another parameter in the same section or an earlier one
+ def precise0(y: x.type)(x: String): Unit = {}
+ ^
+depmet_1.scala:3: error: illegal dependent method type: parameter appears in the type of another parameter in the same section or an earlier one
+ def precise1(x: String, y: x.type): Unit = {}
+ ^
+depmet_1.scala:4: error: not found: value y
+ def precise2[T <: y.type](y: String): Unit = {}
+ ^
+three errors found
diff --git a/test/files/neg/depmet_1.flags b/test/files/neg/depmet_1.flags
new file mode 100644
index 0000000000..1c26b24745
--- /dev/null
+++ b/test/files/neg/depmet_1.flags
@@ -0,0 +1 @@
+-Ydependent-method-types \ No newline at end of file
diff --git a/test/files/neg/depmet_1.scala b/test/files/neg/depmet_1.scala
new file mode 100644
index 0000000000..fc672e1ed8
--- /dev/null
+++ b/test/files/neg/depmet_1.scala
@@ -0,0 +1,5 @@
+object Test {
+ def precise0(y: x.type)(x: String): Unit = {}
+ def precise1(x: String, y: x.type): Unit = {}
+ def precise2[T <: y.type](y: String): Unit = {}
+} \ No newline at end of file
diff --git a/test/files/pos/depmet_1.flags b/test/files/pos/depmet_1.flags
new file mode 100644
index 0000000000..1c26b24745
--- /dev/null
+++ b/test/files/pos/depmet_1.flags
@@ -0,0 +1 @@
+-Ydependent-method-types \ No newline at end of file
diff --git a/test/files/pos/depmet_1.scala b/test/files/pos/depmet_1.scala
new file mode 100644
index 0000000000..166e991817
--- /dev/null
+++ b/test/files/pos/depmet_1.scala
@@ -0,0 +1,6 @@
+object Test {
+ def precise(x: String)(y: x.type): x.type = y
+ val foo = "foo"
+ val fun : foo.type => foo.type = precise(foo)
+ val bar : foo.type = precise(foo)(foo)
+} \ No newline at end of file
diff --git a/test/files/pos/t1569.flags b/test/files/pos/t1569.flags
new file mode 100644
index 0000000000..1c26b24745
--- /dev/null
+++ b/test/files/pos/t1569.flags
@@ -0,0 +1 @@
+-Ydependent-method-types \ No newline at end of file
diff --git a/test/files/pos/t1569.scala b/test/files/pos/t1569.scala
new file mode 100644
index 0000000000..e5f9553268
--- /dev/null
+++ b/test/files/pos/t1569.scala
@@ -0,0 +1,5 @@
+object Bug {
+ class C { type T }
+ def foo(x: Int)(y: C)(z: y.T) {}
+ foo(3)(new C { type T = String })("hello")
+} \ No newline at end of file
diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check
index cc00a7c46b..8050017659 100644
--- a/test/files/run/constrained-types.check
+++ b/test/files/run/constrained-types.check
@@ -52,8 +52,8 @@ val y = b.y // should keep the annotation
y: Int @Annot(Stuff.x) = 10
-----
-def m(x: String): String @Annot(x) = x // m should be annotated with a debruijn
-m: (x$0:String)String @Annot(x)
+def m(x: String): String @Annot(x) = x
+m: (x: String)String @Annot(x)
-----
val three = "three"
diff --git a/test/files/run/constrained-types.scala b/test/files/run/constrained-types.scala
index 59fd0b1b8c..c03c144ad1 100644
--- a/test/files/run/constrained-types.scala
+++ b/test/files/run/constrained-types.scala
@@ -45,7 +45,7 @@ object Test {
"val y = b.y // should keep the annotation",
- "def m(x: String): String @Annot(x) = x // m should be annotated with a debruijn",
+ "def m(x: String): String @Annot(x) = x",
"val three = \"three\"",
"val three2 = m(three:three.type) // should change x to three",
"var four = \"four\"",