summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-04-23 13:00:25 +0000
committerMartin Odersky <odersky@gmail.com>2009-04-23 13:00:25 +0000
commitaaf919859f5dfa295aac8846bc109ceb87984a7e (patch)
tree7b117c12aec2ee0e52a011867f8eb0eaea819b54 /src/compiler/scala/tools
parent4ae08113a6a1708ac53bd84b938c2a233df80476 (diff)
downloadscala-aaf919859f5dfa295aac8846bc109ceb87984a7e.tar.gz
scala-aaf919859f5dfa295aac8846bc109ceb87984a7e.tar.bz2
scala-aaf919859f5dfa295aac8846bc109ceb87984a7e.zip
some small changes to implicits handling, exist...
some small changes to implicits handling, existential abstraction, type parameter bounds checking
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala25
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala95
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala29
7 files changed, 118 insertions, 45 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 3a4fa76891..52b8838c04 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1426,6 +1426,7 @@ abstract class GenICode extends SubComponent {
case Some(local) => local
case None =>
val local = ctx.makeLocal(l.pos, definitions.AnyRefClass.typeConstructor, eqEqTempName.toString)
+ //assert(!l.pos.source.isEmpty, "bad position, unit = "+unit+", tree = "+l+", pos = "+l.pos.source)
assert(l.pos.source.get == unit.source)
assert(r.pos.source.get == unit.source)
local.start = (l.pos).line.get
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 021a3e1dbe..106b737672 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -342,6 +342,8 @@ trait Symbols {
final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME.toTypeName; // no lifting for refinement classes
final def isModuleClass = isClass && hasFlag(MODULE)
final def isPackageClass = isClass && hasFlag(PACKAGE)
+ final def isPackageObjectClass = isModuleClass && name.toTermName == nme.PACKAGEkw && owner.isPackageClass
+ final def definedInPackage = owner.isPackageClass || owner.isPackageObjectClass
final def isRoot = isPackageClass && name == nme.ROOT.toTypeName
final def isRootPackage = isPackage && name == nme.ROOTPKG
final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME
@@ -1357,6 +1359,8 @@ trait Symbols {
override def toString(): String =
if (isValueParameter && owner.isSetter)
"parameter of setter "+owner.nameString
+ else if (isPackageObjectClass)
+ "package object "+nameString
else
compose(List(kindString,
if (isClassConstructor) owner.simpleName.decode+idString else nameString))
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index dab101a15f..9aa29a7395 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1826,8 +1826,14 @@ A type's typeSymbol should never be inspected directly.
override def safeToString =
pre.toString + targs.mkString("(with type arguments ", ",", ")");
override def memberType(sym: Symbol) = pre.memberType(sym) match {
- case PolyType(tparams, restp) => restp.subst(tparams, targs)
- case ErrorType => ErrorType
+ case PolyType(tparams, restp) =>
+ restp.subst(tparams, targs)
+/* I don't think this is needed, as existential types close only over value types
+ case ExistentialType(tparams, qtpe) =>
+ existentialAbstraction(tparams, qtpe.memberType(sym))
+*/
+ case ErrorType =>
+ ErrorType
}
override def kind = "AntiPolyType"
}
@@ -2206,10 +2212,11 @@ A type's typeSymbol should never be inspected directly.
* referenced by type `tpe1'.
* If there are no remaining type parameters, simply returns result type `tpe'.
*/
- def existentialAbstraction(tparams: List[Symbol], tpe: Type): Type =
- if (tparams.isEmpty) tpe
+ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type =
+ if (tparams.isEmpty) tpe0
else {
var occurCount = emptySymCount ++ (tparams map (_ -> 0))
+ val tpe = deAlias(tpe0)
for (t <- tpe) {
t match {
case TypeRef(_, sym, _) =>
@@ -2272,6 +2279,16 @@ A type's typeSymbol should never be inspected directly.
}
}
+ /** Remove any occurrences of type aliases from this type */
+ object deAlias extends TypeMap {
+ def apply(tp: Type): Type = mapOver {
+ tp match {
+ case TypeRef(pre, sym, args) if sym.isAliasType => tp.normalize
+ case _ => tp
+ }
+ }
+ }
+
/** Remove any occurrence of type <singleton> from this type and its parents */
object dropSingletonType extends TypeMap {
def apply(tp: Type): Type = {
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index fbd0ad6385..c9a43270a1 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -121,9 +121,11 @@ abstract class Constructors extends Transform {
// Create an assignment to class field `to' with rhs `from'
def mkAssign(to: Symbol, from: Tree): Tree =
localTyper.typed {
- atPos(to.pos) {
- Assign(Select(This(clazz), to), from)
- }
+ //util.trace("compiling "+unit+" ") {
+ atPos(to.pos) {
+ Assign(Select(This(clazz), to), from)
+ }
+ //}
}
// Create code to copy parameter to parameter accessor field.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 6c7a126ccc..9bc6968e02 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -287,7 +287,7 @@ self: Analyzer =>
*/
val wildPt = approximate(pt)
- if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+info.tpe+"/"+undetParams)
+ //if (traceImplicits) println("typed impl for "+wildPt+"? "+info.name+":"+info.tpe+"/"+undetParams)
if (isPlausiblyCompatible(info.tpe, wildPt) &&
isCompatible(depoly(info.tpe), wildPt) &&
isStable(info.pre)) {
@@ -296,7 +296,7 @@ self: Analyzer =>
if (info.pre == NoPrefix) Ident(info.name)
else Select(gen.mkAttributedQualifier(info.pre), info.name)
}
- if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with "+wildPt)
+ //if (traceImplicits) println("typed impl?? "+info.name+":"+info.tpe+" ==> "+itree+" with "+wildPt)
def fail(reason: String): SearchResult = {
if (settings.XlogImplicits.value)
inform(itree+" is not a valid implicit value for "+pt0+" because:\n"+reason)
@@ -488,33 +488,76 @@ self: Analyzer =>
List()
}
+ /** The parts of a type is the smallest set of types that contains
+ * - the type itself
+ * - the parts of its immediate components (prefix and argument)
+ * - the parts of its base types
+ */
+ private def parts(tp: Type): List[Type] = {
+ val partMap = new collection.jcl.LinkedHashMap[Symbol, List[Type]]
+ /** Add a new type to partMap, unless a subtype of it with the same
+ * type symbol exists already.
+ */
+ def addType(newtp: Type): Boolean = {
+ val tsym = newtp.typeSymbol
+ partMap.get(tsym) match {
+ case Some(ts) =>
+ if (ts exists (_ <:< newtp)) false
+ else { partMap.put(tsym, newtp :: ts); true }
+ case None =>
+ partMap.put(tsym, List(newtp)); true
+ }
+ }
+ /** Enter all parts of `tp` into `partMap`
+ */
+ def getParts(tp: Type) {
+ tp match {
+ case TypeRef(pre, sym, args) if (!sym.isPackageClass) =>
+ if (sym.isClass && !sym.isRefinementClass && !sym.isAnonymousClass) {
+ if (addType(tp)) {
+ for (bc <- sym.info.baseClasses.tail)
+ getParts(tp.baseType(bc))
+ getParts(pre)
+ args foreach getParts
+ }
+ } else if (sym.isAliasType) {
+ getParts(tp.normalize)
+ } else if (sym.isAbstractType) {
+ getParts(tp.bounds.hi)
+ }
+ case ThisType(_) =>
+ getParts(tp.widen)
+ case _: SingletonType =>
+ getParts(tp.widen)
+ case RefinedType(ps, _) =>
+ for (p <- ps) getParts(p)
+ case AnnotatedType(_, t, _) =>
+ getParts(t)
+ case ExistentialType(tparams, t) =>
+ getParts(t)
+ case _ =>
+ }
+ }
+ /** Gives a list of typerefs with the same type symbol,
+ * remove all those that have a prefix which is a supertype
+ * of some other elements's prefix.
+ */
+ def compactify(ts: List[Type]): List[Type] = ts match {
+ case List() => ts
+ case (t @ TypeRef(pre, _, _)) :: ts1 =>
+ if (ts1 exists (_.prefix <:< pre)) compactify(ts1)
+ else t :: compactify(ts1 remove (pre <:< _.prefix))
+ }
+ getParts(tp)
+ for ((k, ts) <- partMap.elements.toList; t <- compactify(ts)) yield t
+ }
+
/** The implicits made available by type `pt`.
* These are all implicits found in companion objects of classes C
* such that some part of `tp` has C as one of its superclasses.
*/
- private def implicitsOfExpectedType: List[List[ImplicitInfo]] = {
- def getParts(tp: Type, s: collection.jcl.Set[Type]) {
- tp match {
- case TypeRef(pre, sym, args) if (!sym.isPackageClass) =>
- for (bc <- sym.info.baseClasses)
- if (sym.isClass) s add (tp.baseType(bc))
- getParts(pre, s)
- for (arg <- args) getParts(arg, s)
- case ThisType(_) =>
- getParts(tp.widen, s)
- case _: SingletonType =>
- getParts(tp.widen, s)
- case RefinedType(ps, _) =>
- for (p <- ps) getParts(p, s)
- case AnnotatedType(_, t, _) =>
- getParts(t, s)
- case _ =>
- }
- }
- val tps = new collection.jcl.LinkedHashSet[Type]
- getParts(pt, tps)
- tps.elements.map(implicitsOfClass).toList
- }
+ private def implicitsOfExpectedType: List[List[ImplicitInfo]] =
+ parts(pt).elements.map(implicitsOfClass).toList
/** The manifest corresponding to type `pt`, provided `pt` is an instance of Manifest.
*/
@@ -598,6 +641,8 @@ self: Analyzer =>
val resultTree = implicitManifest(pt)
if (resultTree != EmptyTree) result = new SearchResult(resultTree, EmptyTreeTypeSubstituter)
}
+ if (result == SearchFailure && settings.verbose.value) //!!!
+ println("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+parts(pt)+implicitsOfExpectedType)
if (util.Statistics.enabled) impltime += (currentTime - startTime)
result
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 3e267fcda2..fb018647ff 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -463,6 +463,7 @@ trait Infer {
case _ =>
restpe
}
+ //println("try to solve "+tvars+" "+tparams)
solvedTypes(tvars, tparams, tparams map varianceInType(varianceType),
false, lubDepth(List(restpe, pt)))
} catch {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index dec6d58b45..35442e10e7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -571,10 +571,12 @@ trait Typers { self: Analyzer =>
case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw)
}
}
- val tree1 = tree match {
- case Ident(name) => Select(qual, name)
- case Select(_, name) => Select(qual, name)
- case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name)
+ val tree1 = atPos(tree.pos) {
+ tree match {
+ case Ident(name) => Select(qual, name)
+ case Select(_, name) => Select(qual, name)
+ case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name)
+ }
}
val tree2 = checkAccessible(tree1, sym, qual.tpe, qual)
tree2
@@ -745,7 +747,7 @@ trait Typers { self: Analyzer =>
context.undetparams = context.undetparams ::: tparams1
adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt)
case mt: ImplicitMethodType if ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1)
- if (!context.undetparams.isEmpty && (mode & POLYmode) == 0) { // (9)
+ if (!context.undetparams.isEmpty/* && (mode & POLYmode) == 0 disabled to make implicits in new collection work; we should revisit this. */) { // (9)
context.undetparams = inferExprInstance(
tree, context.extractUndetparams(), pt, mt.paramTypes exists isManifest)
// if we are looking for a manifest, instantiate type to Nothing anyway,
@@ -1479,12 +1481,13 @@ trait Typers { self: Analyzer =>
val typedMods = typedModifiers(tdef.mods)
val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs))
checkNonCyclic(tdef.symbol)
- rhs1.tpe match {
- case TypeBounds(lo1, hi1) =>
- if (!(lo1 <:< hi1))
- error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1)
- case _ =>
- }
+ if (tdef.symbol.owner.isType)
+ rhs1.tpe match {
+ case TypeBounds(lo1, hi1) =>
+ if (!(lo1 <:< hi1))
+ error(tdef.pos, "lower bound "+lo1+" does not conform to upper bound "+hi1)
+ case _ =>
+ }
copy.TypeDef(tdef, typedMods, tdef.name, tparams1, rhs1) setType NoType
}
@@ -2516,7 +2519,7 @@ trait Typers { self: Analyzer =>
copy.Assign(tree, lhs1, checkDead(rhs1)) setType UnitClass.tpe
} else {
if (!lhs1.tpe.isError) {
- //println(lhs1+" = "+rhs)//DEBUG
+ //println(lhs1+" = "+rhs+" "+varsym+" "+mayBeVarGetter(varsym)+" "+varsym.ownerChain+" "+varsym.info)// DEBUG
error(tree.pos,
if ((varsym ne null) && varsym.isValue) "reassignment to val"
else "assignment to non variable")
@@ -3064,7 +3067,7 @@ trait Typers { self: Analyzer =>
if (defSym.exists && impSym.exists) {
// imported symbols take precedence over package-owned symbols in different
// compilation units. Defined symbols take precedence over errenous imports.
- if (defSym.owner.isPackageClass &&
+ if (defSym.definedInPackage &&
((!inIDE && !currentRun.compiles(defSym)) ||
(context.unit ne null) && defSym.sourceFile != context.unit.source.file))
defSym = NoSymbol