summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Namers.scala
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/nsc/typechecker/Namers.scala
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/nsc/typechecker/Namers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala111
1 files changed, 40 insertions, 71 deletions
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