summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-01-17 16:37:27 +0000
committerMartin Odersky <odersky@gmail.com>2008-01-17 16:37:27 +0000
commit76c06b4661b70e934530a0debad34a5766ee43e9 (patch)
tree4abb85699a2d663681a9ca31fb7ccff45b80746f /src
parente5ca1a3906ae29c1d6db5de333932bbfc189cedc (diff)
downloadscala-76c06b4661b70e934530a0debad34a5766ee43e9.tar.gz
scala-76c06b4661b70e934530a0debad34a5766ee43e9.tar.bz2
scala-76c06b4661b70e934530a0debad34a5766ee43e9.zip
build target is now 1.5
case classes now generate objects not factory methods. some small cleanups for type inference
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala21
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala2
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Flags.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala16
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala37
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala9
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala111
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala125
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala109
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala88
-rw-r--r--src/library/scala/collection/jcl/SortedSet.scala4
21 files changed, 403 insertions, 191 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 1aaa2f41bf..f37a34ae74 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -18,6 +18,21 @@ abstract class TreeGen {
import definitions._
import posAssigner.atPos
+ def scalaDot(name: Name): Tree =
+ Select(Ident(nme.scala_) setSymbol ScalaPackage, name)
+ def scalaAnyRefConstr: Tree =
+ scalaDot(nme.AnyRef.toTypeName)
+ def scalaUnitConstr: Tree =
+ scalaDot(nme.Unit.toTypeName)
+ def scalaScalaObjectConstr: Tree =
+ scalaDot(nme.ScalaObject.toTypeName)
+ def productConstr: Tree =
+ scalaDot(nme.Product.toTypeName)
+
+ def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(
+ scalaDot(newTypeName("Function"+argtpes.length)),
+ argtpes ::: List(restpe))
/** Builds a reference to value whose type is given stable prefix.
* The type must be suitable for this. For example, it
@@ -135,7 +150,6 @@ abstract class TreeGen {
This(sym.name) setSymbol sym setType sym.thisType
def mkAttributedIdent(sym: Symbol): Tree = {
- assert(sym.isTerm, sym)
Ident(sym.name) setSymbol sym setType sym.tpe
}
@@ -145,7 +159,6 @@ abstract class TreeGen {
qual.symbol.name.toTermName == nme.EMPTY_PACKAGE_NAME)) {
mkAttributedIdent(sym)
} else {
- assert(sym.isTerm)
val result = Select(qual, sym.name) setSymbol sym
if (qual.tpe ne null) result setType qual.tpe.memberType(sym)
result
@@ -207,7 +220,9 @@ abstract class TreeGen {
/** Builds a tuple */
def mkTuple(elems: List[Tree]): Tree =
if (elems.isEmpty) Literal(())
- else Apply(mkAttributedRef(definitions.TupleClass(elems.length).caseFactory), elems)
+ else Apply(
+ Select(mkAttributedRef(definitions.TupleClass(elems.length).caseModule), nme.apply),
+ elems)
def mkAnd(tree1: Tree, tree2: Tree) =
Apply(Select(tree1, Boolean_and), List(tree2))
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
index d814c5cd6c..b6dd026a84 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -244,22 +244,6 @@ abstract class TreeInfo {
case _ => false
}
- /** is this pattern of the form S(...) where S is a subclass of Seq
- * and S is not a case class? The pattern might be wrapped in binds or alternatives.
- */
- def isSequencePattern(tree: Tree): Boolean = tree match {
- case Apply(fn, _) =>
- (fn.symbol ne null) &&
- !fn.symbol.hasFlag(CASE) &&
- fn.symbol.isNonBottomSubClass(definitions.SeqClass)
- case Bind(name, body) =>
- isSequencePattern(body)
- case Alternative(ts) =>
- ts forall isSequencePattern
- case _ =>
- false
- }
-
/** The method part of an application node
*/
def methPart(tree: Tree): Tree = tree match {
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 4412aa0896..81f10c7a31 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -755,6 +755,8 @@ trait Trees {
case class TypeTree() extends TypTree {
var original: Tree = _
+ override def symbol = tpe.typeSymbol
+
def setOriginal(tree: Tree): this.type = {
original = tree
setPos(tree.pos)
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 4fb9f310b1..b7355c86ff 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -244,7 +244,7 @@ abstract class DeadCodeElimination extends SubComponent {
def find(bb: BasicBlock): Option[(BasicBlock, Int)] = {
var xs = bb.toList
xs.zipWithIndex find { hd => hd._1 eq i } match {
- case Some(_, idx) => Some(bb, idx)
+ case Some((_, idx)) => Some(bb, idx)
case None => None
}
}
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index d019b4cc89..6814ef7465 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -673,9 +673,9 @@ trait ParallelMatching {
pat match {
case Bind(_,p) =>
subpatterns(p)
- case app @ Apply(fn, pats) if isCaseClass(app.tpe) && (fn.symbol eq null)=>
+ case app @ Apply(fn, pats) if isCaseClass(app.tpe) && fn.isType =>
if (isCaseHead) pats else dummies
- case Apply(fn,xs) => assert((xs.isEmpty) && (fn.symbol ne null), "strange Apply"); dummies // named constant
+ case Apply(fn,xs) => assert((xs.isEmpty) && (!fn.isType), "strange Apply"); dummies // named constant
case _: UnApply =>
dummies
case pat =>
@@ -1230,7 +1230,7 @@ trait ParallelMatching {
*/
final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match {
case Nil =>
- ErrorRule
+ ErrorRule()
case Row(pats, subst, g, bx)::xs =>
var px = 0; var rpats = pats; var bnd = subst; var temps = temp; while((bnd ne null) && (rpats ne Nil)) {
val (vs,p) = strip(rpats.head);
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index 92b59ff20f..030e46175f 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -78,14 +78,14 @@ trait PatternNodes { self: transform.ExplicitOuter =>
}
object Apply_Value {
- def unapply(x:Apply) = if ((x.symbol ne null) && (x.args eq Nil)) Some(x.tpe.prefix, x.symbol) else None
+ def unapply(x:Apply) = if (!x.fun.isType && x.args.isEmpty) Some(x.tpe.prefix, x.symbol) else None
}
object Apply_CaseClass_NoArgs {
- def unapply(x:Apply) = if ((x.symbol eq null) && (x.args eq Nil)) Some(x.tpe) else None
+ def unapply(x:Apply) = if (x.fun.isType && x.args.isEmpty) Some(x.tpe) else None
}
object Apply_CaseClass_WithArgs {
- def unapply(x:Apply) = if (x.symbol eq null) true else false
+ def unapply(x:Apply) = x.fun.isType
}
object __UnApply {
diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala
index eefc6457e4..7befdc9719 100644
--- a/src/compiler/scala/tools/nsc/symtab/Flags.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala
@@ -126,7 +126,7 @@ object Flags extends Enumeration {
final val PickledFlags: Long = 0xFFFFFFFFL
/** Module flags inherited by their module-class */
- final val ModuleToClassFlags: Long = AccessFlags | PACKAGE | CASE
+ final val ModuleToClassFlags: Long = AccessFlags | MODULE | PACKAGE | CASE | SYNTHETIC
private def listToString(ss: List[String]): String =
ss.filter("" !=).mkString("", " ", "")
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 68e5e35f60..f6a2904a45 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -215,6 +215,7 @@ trait StdNames {
val Finally = newTermName("Finally")
val Float = newTermName("Float")
val Function = newTermName("Function")
+ val Function1 = newTermName("Function1")
val Int = newTermName("Int")
val Labelled = newTermName("Labelled")
val Long = newTermName("Long")
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 5bec708d45..e085c13e9c 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -261,9 +261,9 @@ trait Symbols {
final def isPrimaryConstructor =
isConstructor && owner.primaryConstructor == this
- /** Is this symbol a case class factory method? */
- final def isCaseFactory =
- isMethod && hasFlag(CASE)
+ /** Is this symbol a synthetic apply or unapply method in a companion object of a case class? */
+ final def isCaseApplyOrUnapply =
+ isMethod && hasFlag(CASE) && hasFlag(SYNTHETIC)
/** Is this symbol an implementation class for a mixin? */
final def isImplClass: Boolean = isClass && hasFlag(IMPLCLASS)
@@ -930,14 +930,14 @@ trait Symbols {
final def setter(base: Symbol): Symbol =
base.info.decl(nme.getterToSetter(nme.getterName(name))) filter (_.hasFlag(ACCESSOR))
- /** The case factory corresponding to this case class
+ /** The case module corresponding to this case class
* @pre case class is a member of some other class or package
*/
- final def caseFactory: Symbol = {
- var facname = name.toTermName
+ final def caseModule: Symbol = {
+ var modname = name.toTermName
if (privateWithin.isClass && !privateWithin.isModuleClass && !hasFlag(EXPANDEDNAME))
- facname = privateWithin.expandedName(facname)
- initialize.owner.info.decl(facname).suchThat(_.isCaseFactory)
+ modname = privateWithin.expandedName(modname)
+ initialize.owner.info.decl(modname).suchThat(_.isModule)
}
/** If this symbol is a type parameter skolem (not an existential skolem!)
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index f690766561..1f24ff1bf6 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -139,6 +139,7 @@ trait Types {
override def termSymbol = underlying.termSymbol
override def termSymbolDirect = underlying.termSymbolDirect
override def typeParams = underlying.typeParams
+ override def boundSyms = underlying.boundSyms
override def typeSymbol = underlying.typeSymbol
override def typeSymbolDirect = underlying.typeSymbolDirect
override def widen = underlying.widen
@@ -172,7 +173,6 @@ trait Types {
override def paramSectionCount = 0
override def paramTypes: List[Type] = List()
override def typeArgs = underlying.typeArgs
- override def typeParams = underlying.typeParams
override def notNull = maybeRewrap(underlying.notNull)
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = underlying.instantiateTypeParams(formals, actuals)
override def skolemizeExistential(owner: Symbol, origin: AnyRef) = underlying.skolemizeExistential(owner, origin)
@@ -296,10 +296,14 @@ trait Types {
* the empty list for all other types */
def paramTypes: List[Type] = List()
- /** For a poly type, its type parameters,
+ /** For a (potentially wrapped) poly type, its type parameters,
* the empty list for all other types */
def typeParams: List[Symbol] = List()
+ /** For a (potentially wrapped) poly or existential type, its bound symbols,
+ * the empty list for all other types */
+ def boundSyms: List[Symbol] = List()
+
/** Mixin a NotNull trait unless type already has one */
def notNull: Type =
if (isNotNull || phase.erasedTypes) this else NotNullType(this)
@@ -709,8 +713,8 @@ trait Types {
var skolems: List[Symbol] = List()
for (t <- this) {
t match {
- case ExistentialType(tparams, qtpe) =>
- boundSyms = boundSyms ::: tparams
+ case ExistentialType(quantified, qtpe) =>
+ boundSyms = boundSyms ::: quantified
case TypeRef(_, sym, _) =>
if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym))
skolems = sym :: skolems
@@ -1610,6 +1614,7 @@ A type's typeSymbol should never be inspected directly.
override def decls: Scope = resultType.decls
override def termSymbol: Symbol = resultType.termSymbol
override def typeSymbol: Symbol = resultType.typeSymbol
+ override def boundSyms: List[Symbol] = typeParams
override def prefix: Type = resultType.prefix
override def closure: Array[Type] = resultType.closure
override def closureDepth: Int = resultType.closureDepth
@@ -1654,6 +1659,7 @@ A type's typeSymbol should never be inspected directly.
override def isStable: Boolean = false
override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi))
override def parents = underlying.parents map maybeRewrap
+ override def boundSyms: List[Symbol] = quantified
override def prefix = maybeRewrap(underlying.prefix)
override def typeArgs = underlying.typeArgs map maybeRewrap
override def paramTypes = underlying.paramTypes map maybeRewrap
@@ -2648,8 +2654,22 @@ 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) = tp match {
+ case PolyType(bs, restp) =>
+ val bs1 = cloneSymbols(bs)
+ PolyType(bs1, restp.substSym(bs, bs1))
+ case ExistentialType(bs, restp) =>
+ val bs1 = cloneSymbols(bs)
+ ExistentialType(bs1, restp.substSym(bs, bs1))
+ case _ =>
+ tp
+ }
+
def apply(tp0: Type): Type = if (from.isEmpty) tp0 else {
- val tp = mapOver(tp0)
+ val boundSyms = tp0.boundSyms
+ val tp1 = if (boundSyms.isEmpty || !(boundSyms exists (from contains))) tp0
+ else renameBoundSyms(tp0)
+ val tp = mapOver(tp1)
tp match {
// @M
@@ -2673,13 +2693,6 @@ A type's typeSymbol should never be inspected directly.
}
case SingleType(NoPrefix, sym) =>
subst(tp, sym, from, to)
- case PolyType(tparams, restp) =>
- assert(!(tparams exists (from contains)))
- tp
- case ExistentialType(tparams, restp) =>
- if (tparams exists (from contains))
- assert(false, "["+from.mkString(",")+":="+to.mkString(",")+"]"+tp)
- tp
case _ =>
tp
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index b03c05ce3b..d7150d981f 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -154,12 +154,18 @@ abstract class Constructors extends Transform {
if (stat.symbol.tpe.isInstanceOf[ConstantType])
assert(stat.symbol.getter(stat.symbol.owner) != NoSymbol, stat)
else {
+ try {
if (rhs != EmptyTree && !stat.symbol.hasFlag(LAZY)) {
val rhs1 = intoConstructor(stat.symbol, rhs);
(if (canBeMoved(stat)) constrPrefixBuf else constrStatBuf) += mkAssign(
stat.symbol, rhs1)
}
defBuf += copy.ValDef(stat, mods, name, tpt, EmptyTree)
+ } catch {
+ case ex: Throwable =>
+ println("error when transforming "+stat+" in "+stats)
+ throw ex
+ }
}
case ClassDef(_, _, _, _) =>
defBuf += (new ConstructorTransformer).transform(stat)
@@ -205,14 +211,13 @@ abstract class Constructors extends Transform {
defBuf.toList filter (stat => isAccessed(stat.symbol)))
}
- override def transform(tree: Tree): Tree = {
+ override def transform(tree: Tree): Tree =
tree match {
case ClassDef(mods, name, tparams, impl) if !tree.symbol.hasFlag(INTERFACE) =>
copy.ClassDef(tree, mods, name, tparams, transformClassTemplate(impl))
case _ =>
super.transform(tree)
}
- }
} // ConstructorTransformer
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 80a1fc1f0c..a83c68f797 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -763,7 +763,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
*/
private val preTransformer = new Transformer {
override def transform(tree: Tree): Tree = {
- if (tree.symbol == ArrayClass) return tree
+ if (tree.symbol == ArrayClass && !tree.isType) return tree
val tree1 = tree match {
case ClassDef(mods, name, tparams, impl) =>
if (settings.debug.value)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 8bf0994af6..144081efcb 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -59,7 +59,7 @@ abstract class Mixin extends InfoTransform {
* inherits the trait.
*/
private def isForwarded(sym: Symbol) =
- isImplementedStatically(sym) && !sym.isImplOnly && !sym.isCaseFactory
+ isImplementedStatically(sym) && !sym.isImplOnly
/** Maps the type of an implementation class to its interface;
* maps all other types to themselves.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index defcc6ce2e..4ede3dec3b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -35,7 +35,7 @@ trait Analyzer extends AnyRef
val global: Analyzer.this.global.type = Analyzer.this.global
val phaseName = "typer"
def newPhase(_prev: Phase): StdPhase = new StdPhase(_prev) {
- resetTyper
+ resetTyper()
def apply(unit: CompilationUnit) {
unit.body = newTyper(rootContext(unit)).typed(unit.body)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index f0311dd885..782c003b25 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -76,7 +76,7 @@ trait Contexts { self: Analyzer =>
c
}
- def resetContexts {
+ def resetContexts() {
var sc = startContext
while (sc != NoContext) {
sc.tree match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 8571148479..ea2a4c59c8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -512,12 +512,33 @@ trait Infer {
if (targ.typeSymbol == AllClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) {
uninstantiated += tparam
tparam.tpe //@M TODO: might be affected by change to tpe in Symbol
- } else targ.widen
+ } else if (targ.typeSymbol == RepeatedParamClass) {
+ targ.baseType(SeqClass)
+ } else {
+ targ.widen
+ }
}
// println("meth type args "+", tparams = "+tparams+", formals = "+formals+", restpe = "+restpe+", argtpes = "+argtpes+", underlying = "+(argtpes map (_.widen))+", pt = "+pt+", uninstantiated = "+uninstantiated.toList+", result = "+res) //DEBUG
// res
}
+ def followApply(tp: Type): Type = tp match {
+ case PolyType(List(), restp) =>
+ val restp1 = followApply(restp)
+ if (restp1 eq restp) tp else restp1
+ case _ =>
+ val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ if (appmeth == NoSymbol) tp
+ else OverloadedType(tp, appmeth.alternatives)
+ }
+
+ def hasExactlyNumParams(tp: Type, n: Int): Boolean = tp match {
+ case OverloadedType(pre, alts) =>
+ alts exists (alt => hasExactlyNumParams(pre.memberType(alt), n))
+ case _ =>
+ formalTypes(tp.paramTypes, n).length == n
+ }
+
/** Is there an instantiation of free type variables <code>undetparams</code>
* such that function type <code>ftpe</code> is applicable to
* <code>argtpes</code> and its result conform to <code>pt</code>?
@@ -531,6 +552,8 @@ trait Infer {
def isApplicable(undetparams: List[Symbol], ftpe: Type,
argtpes0: List[Type], pt: Type): Boolean =
ftpe match {
+ case OverloadedType(pre, alts) =>
+ alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt))
case ExistentialType(tparams, qtpe) =>
isApplicable(undetparams, qtpe, argtpes0, pt)
case MethodType(formals0, _) =>
@@ -573,29 +596,70 @@ trait Infer {
}
}
- /** Does type <code>ftpe1</code> specialize type <code>ftpe2</code>
+ /** Is type <code>ftpe1</code> strictly more specific than type <code>ftpe2</code>
* when both are alternatives in an overloaded function?
+ * @see SLS (sec:overloading-resolution)
*
* @param ftpe1 ...
* @param ftpe2 ...
* @return ...
*/
- def specializes(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match {
+ def isMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean = ftpe1 match {
+ case OverloadedType(pre, alts) =>
+ alts exists (alt => isMoreSpecific(pre.memberType(alt), ftpe2))
case et: ExistentialType =>
- et.withTypeVars(specializes(_, ftpe2))
- case MethodType(formals, _) =>
+ et.withTypeVars(isStrictlyMoreSpecific(_, ftpe2))
+ case MethodType(formals @ (x :: xs), _) =>
isApplicable(List(), ftpe2, formals, WildcardType)
- case PolyType(tparams, MethodType(formals, _)) =>
+ case PolyType(_, MethodType(formals @ (x :: xs), _)) =>
isApplicable(List(), ftpe2, formals, WildcardType)
case ErrorType =>
true
case _ =>
- false
+ ftpe2 match {
+ case OverloadedType(pre, alts) =>
+ alts forall (alt => isMoreSpecific(ftpe1, pre.memberType(alt)))
+ case et: ExistentialType =>
+ et.withTypeVars(isStrictlyMoreSpecific(ftpe1, _))
+ case MethodType(_, _) | PolyType(_, MethodType(_, _)) =>
+ true
+ case _ =>
+ isMoreSpecificValueType(ftpe1, ftpe2, List(), List())
+ }
}
+ def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type): Boolean =
+ ftpe1.isError || isMoreSpecific(ftpe1, ftpe2) &&
+ (!isMoreSpecific(ftpe2, ftpe1) ||
+ !ftpe1.isInstanceOf[OverloadedType] && ftpe2.isInstanceOf[OverloadedType])
+
+ def isMoreSpecificValueType(tpe1: Type, tpe2: Type, undef1: List[Symbol], undef2: List[Symbol]): Boolean = (tpe1, tpe2) match {
+ case (PolyType(tparams1, rtpe1), _) =>
+ isMoreSpecificValueType(rtpe1, tpe2, undef1 ::: tparams1, undef2)
+ case (_, PolyType(tparams2, rtpe2)) =>
+ isMoreSpecificValueType(tpe1, rtpe2, undef1, undef2 ::: tparams2)
+ case _ =>
+ existentialAbstraction(undef1, tpe1) <:< existentialAbstraction(undef2, tpe2)
+ }
+
+/*
/** Is type `tpe1' a strictly better expression alternative than type `tpe2'?
*/
def isStrictlyBetterExpr(tpe1: Type, tpe2: Type) = {
+ isMethod(tpe2) && !isMethod(tpe1) ||
+ isNullary(tpe1) && !isNullary(tpe2) ||
+ isStrictlyBetter(tpe1, tpe2)
+ }
+
+ /** Is type `tpe1' a strictly better alternative than type `tpe2'?
+ * non-methods are always strictly better than methods
+ * nullary methods are always strictly better than non-nullary
+ * if both are non-nullary methods, then tpe1 is strictly better than tpe2 if
+ * - tpe1 specializes tpe2 and tpe2 does not specialize tpe1
+ * - tpe1 and tpe2 specialize each other and tpe1 has a strictly better resulttype than
+ * tpe2
+ */
+ def isStrictlyBetter(tpe1: Type, tpe2: Type) = {
def isNullary(tpe: Type): Boolean = tpe match {
case tp: RewrappingTypeProxy => isNullary(tp.underlying)
case _ => tpe.paramSectionCount == 0 || tpe.paramTypes.isEmpty
@@ -605,16 +669,21 @@ trait Infer {
case MethodType(_, _) | PolyType(_, _) => true
case _ => false
}
- isMethod(tpe2) && !isMethod(tpe1) ||
+ def hasStrictlyBetterResult =
+ resultIsBetter(tpe1, tpe2, List(), List()) && !resultIsBetter(tpe2, tpe1, List(), List())
+ if (!isMethod(tpe1))
+ isMethod(tpe2) || hasStrictlyBetterResult
+
isNullary(tpe1) && !isNullary(tpe2) ||
- isStrictlyBetter(tpe1, tpe2)
- }
+ is
- /** Is type `tpe1' a strictly better alternative than type `tpe2'?
- */
- def isStrictlyBetter(tpe1: Type, tpe2: Type) =
- specializes(tpe1, tpe2) && !specializes(tpe2, tpe1)
+ else if (isNullary(tpe1))
+ isMethod(tpe2) && (!isNullary(tpe2) || hasStrictlyBetterResult)
+ else
+ specializes(tpe1, tpe2) && (!specializes(tpe2, tpe1) || hasStrictlyBetterResult)
+ }
+*/
/** error if arguments not within bounds. */
def checkBounds(pos: Position, pre: Type, owner: Symbol,
tparams: List[Symbol], targs: List[Type], prefix: String) = {
@@ -715,7 +784,7 @@ trait Infer {
else if (s.isContravariant) "contravariant"
else "invariant";
- def qualify(a0: Symbol, b0: Symbol): String = if(a0.toString != b0.toString) "" else {
+ def qualify(a0: Symbol, b0: Symbol): String = if (a0.toString != b0.toString) "" else {
assert((a0 ne b0) && (a0.owner ne b0.owner));
var a = a0; var b = b0
while (a.owner.name == b.owner.name) { a = a.owner; b = b.owner}
@@ -1123,7 +1192,7 @@ trait Infer {
*/
def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match {
case OverloadedType(pre, alts) => tryTwice {
- var alts1 = alts filter (alt => isCompatible(pre.memberType(alt), pt))
+ var alts1 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt))
var secondTry = false
if (alts1.isEmpty) {
alts1 = alts
@@ -1134,8 +1203,8 @@ trait Infer {
{ val tp1 = pre.memberType(sym1)
val tp2 = pre.memberType(sym2)
(tp2 == ErrorType ||
- !global.typer.infer.isCompatible(tp2, pt) && global.typer.infer.isCompatible(tp1, pt) ||
- isStrictlyBetterExpr(tp1, tp2)) }
+ !global.typer.infer.isWeaklyCompatible(tp2, pt) && global.typer.infer.isWeaklyCompatible(tp1, pt) ||
+ isStrictlyMoreSpecific(tp1, tp2)) }
val best = ((NoSymbol: Symbol) /: alts1) ((best, alt) =>
if (improves(alt, best)) alt else best)
val competing = alts1 dropWhile (alt => best == alt || improves(best, alt))
@@ -1161,7 +1230,7 @@ trait Infer {
}
} else {
val applicable = alts1 filter (alt =>
- global.typer.infer.isCompatible(pre.memberType(alt), pt))
+ global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt))
checkNotShadowed(tree.pos, pre, best, applicable)
tree.setSymbol(best).setType(pre.memberType(best))
}
@@ -1180,10 +1249,10 @@ trait Infer {
case OverloadedType(pre, alts) =>
tryTwice {
if (settings.debug.value) log("infer method alt " + tree.symbol + " with alternatives " + (alts map pre.memberType) + ", argtpes = " + argtpes + ", pt = " + pt)
- val applicable = alts filter (alt => isApplicable(undetparams, pre.memberType(alt), argtpes, pt))
+ val applicable = alts filter (alt => isApplicable(undetparams, followApply(pre.memberType(alt)), argtpes, pt))
def improves(sym1: Symbol, sym2: Symbol) =
sym2 == NoSymbol || sym2.isError ||
- isStrictlyBetter(pre.memberType(sym1), pre.memberType(sym2))
+ isStrictlyMoreSpecific(followApply(pre.memberType(sym1)), followApply(pre.memberType(sym2)))
val best = ((NoSymbol: Symbol) /: applicable) ((best, alt) =>
if (improves(alt, best)) alt else best)
val competing = applicable dropWhile (alt => best == alt || improves(best, alt))
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index e236f0f7e7..4f6d1682ad 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -6,6 +6,7 @@
package scala.tools.nsc.typechecker
+import scala.collection.mutable.HashMap
import scala.tools.nsc.util.Position
import symtab.Flags
import symtab.Flags._
@@ -18,6 +19,7 @@ import symtab.Flags._
trait Namers { self: Analyzer =>
import global._
import definitions._
+ import posAssigner.atPos
/** Convert to corresponding type parameters all skolems which satisfy one
* of the following two conditions:
@@ -41,6 +43,12 @@ trait Namers { self: Analyzer =>
private class NormalNamer(context : Context) extends Namer(context)
def newNamer(context : Context) : Namer = new NormalNamer(context)
+ private val caseClassOfModuleClass = new HashMap[Symbol, ClassDef]
+
+ def resetNamer() {
+ caseClassOfModuleClass.clear
+ }
+
abstract class Namer(val context: Context) {
val typer = newTyper(context)
@@ -51,6 +59,14 @@ trait Namers { self: Analyzer =>
sym
}
+
+ def inConstructorFlag: Long =
+ if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR
+ else 0l
+
+ def moduleClassFlags(moduleFlags: Long) =
+ (moduleFlags & ModuleToClassFlags) | FINAL | inConstructorFlag
+
def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = {
if (settings.debug.value) log("overwriting " + sym)
val lockedFlag = sym.flags & LOCKED
@@ -58,7 +74,7 @@ trait Namers { self: Analyzer =>
sym setPos pos
sym.flags = flags | lockedFlag
if (sym.isModule && sym.moduleClass != NoSymbol)
- updatePosFlags(sym.moduleClass, pos, (flags & ModuleToClassFlags) | MODULE | FINAL)
+ updatePosFlags(sym.moduleClass, pos, moduleClassFlags(flags))
if (sym.owner.isPackageClass &&
(sym.linkedSym.rawInfo.isInstanceOf[loaders.SymbolLoader] ||
sym.linkedSym.rawInfo.isComplete && runId(sym.validTo) != currentRunId))
@@ -112,13 +128,20 @@ trait Namers { self: Analyzer =>
!((newS.owner.isTypeParameter || newS.owner.isAbstractType) &&
newS.name.length==1 && newS.name(0)=='_') //@M: allow repeated use of `_' for higher-order type params
}
+
+ // IDE hook
protected def setInfo[Sym <: Symbol](sym : Sym)(tpe : LazyType) : Sym = sym.setInfo(tpe)
+
private def doubleDefError(pos: Position, sym: Symbol) {
context.error(pos,
sym.name.toString() + " is already defined as " +
(if (sym.hasFlag(CASE)) "case class " + sym.name else sym.toString()))
}
+ private def inCurrentScope(m: Symbol) =
+ if (context.owner.isClass) context.owner == m.owner
+ else context.scope == m.owner.info.decls
+
def enterInScope(sym: Symbol): Symbol = {
// allow for overloaded methods
if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) {
@@ -149,10 +172,6 @@ trait Namers { self: Analyzer =>
}
}
- def inConstructorFlag: Long =
- if (context.owner.isConstructor && !context.inConstructorSuffix || context.owner.isEarly) INCONSTRUCTOR
- else 0l
-
def enterClassSymbol(tree : ClassDef): Symbol = {
var c: Symbol = context.scope.lookup(tree.name);
if (!inIDE && c.isType && context.scope == c.owner.info.decls && !currentRun.compiles(c)) {
@@ -179,21 +198,25 @@ trait Namers { self: Analyzer =>
assert(c.name.toString.indexOf('(') == -1)
c
}
+
+ /** Enter a module symbol. The tree parameter can be either a module definition
+ * or a class definition */
def enterModuleSymbol(tree : ModuleDef): Symbol = {
// .pos, mods.flags | MODULE | FINAL, name
- assert(tree.name.isTermName)
var m: Symbol = context.scope.lookup(tree.name)
- if (!inIDE && m.isModule && !m.isPackage && (context.scope == m.owner.info.decls) &&
- !currentRun.compiles(m)) {
- updatePosFlags(m, tree.pos, tree.mods.flags|MODULE|FINAL)
+ val moduleFlags = tree.mods.flags | MODULE | FINAL
+ if (!inIDE && m.isModule && !m.isPackage && inCurrentScope(m) &&
+ (!currentRun.compiles(m) || (m hasFlag SYNTHETIC))) {
+ updatePosFlags(m, tree.pos, moduleFlags)
setPrivateWithin(tree, m, tree.mods)
+ synthetics -= m
} else {
m = context.owner.newModule(tree.pos, tree.name)
- m.setFlag(tree.mods.flags)
+ m.setFlag(moduleFlags)
m = setPrivateWithin(tree, m, tree.mods)
m = enterInScope(m)
- m.moduleClass.setFlag(tree.mods.flags|MODULE|FINAL| inConstructorFlag)
+ m.moduleClass.setFlag(moduleClassFlags(moduleFlags))
setPrivateWithin(tree, m.moduleClass, tree.mods)
}
if (m.owner.isPackageClass) {
@@ -203,26 +226,6 @@ trait Namers { self: Analyzer =>
m
}
- def enterCaseFactorySymbol(tree : ClassDef): Symbol = {
- val pos = tree.pos
- val flags = tree.mods.flags & AccessFlags | METHOD | CASE
- val name = tree.name.toTermName
- var m: Symbol = context.scope.lookup(name)
- if (!inIDE && m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) {
- updatePosFlags(m, pos, flags)
- setPrivateWithin(tree, m, tree.mods)
- } else {
- // recycle the old fashion way.
- m = enterInScope{
- var sym = context.owner.newMethod(pos, name).setFlag(flags)
- sym = setPrivateWithin(tree, sym, tree.mods)
- sym
- }
- }
- if (m.owner.isPackageClass)
- currentRun.symSource(m) = context.unit.source.file
- m
- }
def enterSyms(trees: List[Tree]): Namer = {
var namer : Namer = this
for (tree <- trees) {
@@ -231,6 +234,7 @@ trait Namers { self: Analyzer =>
}
namer
}
+
def newTypeSkolems(tparams: List[Symbol]): List[Symbol] = {
val tskolems = tparams map (_.newTypeSkolem)
val ltp = new LazyType {
@@ -280,7 +284,6 @@ trait Namers { self: Analyzer =>
}
def finish = finishWith(List())
-
if (tree.symbol == NoSymbol) {
val owner = context.owner
tree match {
@@ -292,9 +295,12 @@ trait Namers { self: Analyzer =>
case tree @ ClassDef(mods, name, tparams, impl) =>
tree.symbol = enterClassSymbol(tree)
finishWith(tparams)
- if ((mods.flags & CASE) != 0) { // enter case factory method.
- val sym = enterCaseFactorySymbol(tree)
- setInfo(sym)(namerOf(sym).caseFactoryCompleter(reuse(tree)))
+ if ((mods.flags & CASE) != 0) {
+ var m: Symbol = context.scope.lookup(tree.name.toTermName).filter(! _.isSourceMethod)
+ if (!(m.isModule && inCurrentScope(m) && currentRun.compiles(m))) {
+ m = enterSyntheticSym(caseModuleDef(tree))
+ }
+ caseClassOfModuleClass(m.moduleClass) = tree
}
case tree @ ModuleDef(mods, name, _) =>
tree.symbol = enterModuleSymbol(tree)
@@ -370,6 +376,12 @@ trait Namers { self: Analyzer =>
this.context
}
+ def enterSyntheticSym(tree: Tree): Symbol = {
+ enterSym(tree)
+ synthetics(tree.symbol) = tree
+ tree.symbol
+ }
+
// --- Lazy Type Assignment --------------------------------------------------
def typeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
@@ -421,14 +433,6 @@ trait Namers { self: Analyzer =>
sym.setInfo(selftpe)
}
- def caseFactoryCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
- val clazz = tree.symbol
- var tpe = clazz.primaryConstructor.tpe
- val tparams = clazz.typeParams
- if (!tparams.isEmpty) tpe = PolyType(tparams, tpe).cloneInfo(sym);
- sym.setInfo(tpe)
- }
-
private def widenIfNotFinal(sym: Symbol, tpe: Type, pt: Type): Type = {
val getter =
if (sym.isValue && sym.owner.isClass && (sym hasFlag PRIVATE))
@@ -508,7 +512,14 @@ trait Namers { self: Analyzer =>
val parents = typer.parentTypes(templ) map checkParent
enterSelf(templ.self)
val decls = newClassScope(clazz)
- newNamer(context.make(templ, clazz, decls)).enterSyms(templ.body)
+ val templateNamer = newNamer(context.make(templ, clazz, decls))
+ .enterSyms(templ.body)
+ caseClassOfModuleClass get clazz match {
+ case Some(cdef) =>
+ addApplyUnapply(cdef, templateNamer)
+ caseClassOfModuleClass -= clazz
+ case None =>
+ }
ClassInfoType(parents, decls, clazz)
}
@@ -733,6 +744,28 @@ trait Namers { self: Analyzer =>
else polyType(tparamSyms, tp)
}
+ /** Given a case class
+ *
+ * case class C[Ts] (ps: Us)
+ *
+ * Add the following methods to toScope:
+ *
+ * 1. if case class is not abstract, add
+ *
+ * <synthetic> <case> def apply[Ts](ps: Us): C[Ts] = new C[Ts](ps)
+ *
+ * 2. add a method
+ *
+ * <synthetic> <case> def unapply[Ts](x: C[Ts]) = <ret-val>
+ *
+ * where <ret-val> is the caseClassUnapplyReturnValue of class C (see UnApplies.scala)
+ */
+ def addApplyUnapply(cdef: ClassDef, namer: Namer) {
+ if (!(cdef.symbol hasFlag ABSTRACT))
+ namer.enterSyntheticSym(caseModuleApplyMeth(cdef))
+ namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
+ }
+
def typeSig(tree: Tree): Type = {
val sym: Symbol = tree.symbol
tree match {
@@ -758,7 +791,7 @@ trait Namers { self: Analyzer =>
val clazz = sym.moduleClass
clazz.setInfo(newNamer(context.makeNewScope(tree, clazz)).templateSig(impl))
//clazz.typeOfThis = singleType(sym.owner.thisType, sym);
- clazz.tpe;
+ clazz.tpe
case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
val result =
@@ -884,7 +917,7 @@ trait Namers { self: Analyzer =>
checkNoConflict(PRIVATE, PROTECTED)
checkNoConflict(PRIVATE, OVERRIDE)
checkNoConflict(DEFERRED, FINAL)
- checkNoConflict(ABSTRACT, CASE)
+// checkNoConflict(ABSTRACT, CASE)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 5c7841651b..e098224e59 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -373,7 +373,7 @@ abstract class RefChecks extends InfoTransform {
var state = CoVariance
while (sym != clazz && state != AnyVariance) {
//Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG
- if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseFactory &&
+ if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply &&
!(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem &&
tvar.owner == sym.owner)) state = -state;
else if (!sym.owner.isClass ||
@@ -574,9 +574,6 @@ abstract class RefChecks extends InfoTransform {
}
}
- def isConcreteLocalCaseFactory(clazz: Symbol) =
- (clazz hasFlag CASE) && !(clazz hasFlag ABSTRACT) && !(clazz.owner hasFlag PACKAGE)
-
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
pushLevel()
enterSyms(stats)
@@ -635,32 +632,6 @@ abstract class RefChecks extends InfoTransform {
else transformTrees(List(cdef, vdef, ddef))
}
- case ClassDef(_, _, _, _) if isConcreteLocalCaseFactory(tree.symbol) =>
- val clazz = tree.symbol
- val factory = clazz.caseFactory
- if (factory == NoSymbol) {
- assert(clazz.owner.isTerm, clazz)
- List(transform(tree))
- } else {
- def mkArgument(vparam: Symbol) = {
- val id = Ident(vparam)
- if (vparam.tpe.typeSymbol == RepeatedParamClass) Typed(id, Ident(nme.WILDCARD_STAR.toTypeName))
- else id
- }
- val caseFactoryDef =
- localTyper.typed {
- atPos(tree.pos) {
- DefDef(
- factory,
- vparamss =>
- (toConstructor(tree.pos, factory.tpe) /: vparamss) {
- (fn, vparams) => Apply(fn, vparams map mkArgument)
- })
- }
- }
- List(transform(tree), caseFactoryDef)
- }
-
case ValDef(_, _, _, _) =>
val tree1 = transform(tree); // important to do before forward reference check
val ValDef(_, _, _, rhs) = tree1
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 7429c9ccf7..ff31a95c8a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -38,13 +38,16 @@ trait Typers { self: Analyzer =>
private val superDefs = new HashMap[Symbol, ListBuffer[Tree]]
- def resetTyper {
+ val synthetics = new HashMap[Symbol, Tree]
+
+ def resetTyper() {
resetContexts
+ resetNamer()
transformed.clear
superDefs.clear
+ synthetics.clear
}
-
object UnTyper extends Traverser {
override def traverse(tree: Tree) = {
if (tree != EmptyTree) tree.tpe = null
@@ -708,27 +711,32 @@ trait Typers { self: Analyzer =>
case _ => TypeTree(tree.tpe) setOriginal(tree)
}
} else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) { // (5)
- val constr = tree.symbol.filter(_.isCaseFactory)
- val clazz = constr.tpe.finalResultType.typeSymbol
- if ((constr != NoSymbol) && (clazz hasFlag CASE)) {
- val prefix = tree.tpe.finalResultType.prefix
- val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner)) setOriginal tree
- try {
- inferConstructorInstance(tree1, clazz.typeParams, pt)
- } catch {
- case tpe : TypeError => throw tpe
- case t : Exception =>
- logError("CONTEXT: " + (tree.pos).dbgString, t)
- throw t
- }
- tree1
- } else {
- val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists)
- if (extractor != NoSymbol) {
- tree setSymbol extractor
+ val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists)
+ if (extractor != NoSymbol) {
+ tree setSymbol extractor
+ val unapply = unapplyMember(extractor.tpe)
+ val clazz = if (unapply.tpe.paramTypes.length == 1) unapply.tpe.paramTypes.head.typeSymbol
+ else NoSymbol
+ if ((unapply hasFlag CASE) && (clazz hasFlag CASE)) {
+ if (!phase.erasedTypes) checkStable(tree) //todo: do we need to demand this?
+ // convert synthetic unapply of case class to case class constructor
+ val prefix = tree.tpe.prefix
+ val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner))
+ .setOriginal(tree)
+ try {
+ inferConstructorInstance(tree1, clazz.typeParams, pt)
+ } catch {
+ case tpe : TypeError => throw tpe
+ case t : Exception =>
+ logError("CONTEXT: " + (tree.pos).dbgString, t)
+ throw t
+ }
+ tree1
} else {
- errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
+ tree
}
+ } else {
+ errorTree(tree, tree.symbol + " is not a case class constructor, nor does it have an unapply/unapplySeq method")
}
} else if ((mode & (EXPRmode | FUNmode)) == (EXPRmode | FUNmode) &&
!tree.tpe.isInstanceOf[MethodType] &&
@@ -1440,7 +1448,14 @@ trait Typers { self: Analyzer =>
if (vparam.tpt.isEmpty)
vparam.tpt.tpe =
if (isFullyDefined(argpt)) argpt
- else { error(vparam.pos, "missing parameter type"); ErrorType }
+ else {
+ error(
+ vparam.pos,
+ "missing parameter type"+
+ (if (vparam.mods.hasFlag(SYNTHETIC)) " for expanded function "+fun
+ else ""))
+ ErrorType
+ }
enterSym(context, vparam)
if (context.retyping) context.scope enter vparam.symbol
vparam.symbol
@@ -1479,7 +1494,9 @@ trait Typers { self: Analyzer =>
def typedImport(imp : Import) : Import = imp;
def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
+
val inBlock = exprOwner == context.owner
+
def typedStat(stat: Tree): Tree = {
if (context.owner.isRefinementClass && !treeInfo.isDeclaration(stat))
errorTree(stat, "only declarations allowed here")
@@ -1510,14 +1527,19 @@ trait Typers { self: Analyzer =>
result
}
}
+
def accesses(accessor: Symbol, accessed: Symbol) =
(accessed hasFlag LOCAL) && (accessed hasFlag PARAMACCESSOR) ||
(accessor hasFlag ACCESSOR) &&
!(accessed hasFlag ACCESSOR) && accessed.isPrivateLocal
- def checkNoDoubleDefs(stats: List[Tree]) {
+
+ def checkNoDoubleDefsAndAddSynthetics(stats: List[Tree]): List[Tree] = {
val scope = if (inBlock) context.scope else context.owner.info.decls;
+ val newStats = new ListBuffer[Tree]
var e = scope.elems;
while ((e ne null) && e.owner == scope) {
+
+ // check no double def
var e1 = scope.lookupNextEntry(e);
while ((e1 ne null) && e1.owner == scope) {
if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) &&
@@ -1527,12 +1549,23 @@ trait Typers { self: Analyzer =>
{if(!settings.debug.value) "" else " in "+unit.toString})
e1 = scope.lookupNextEntry(e1);
}
+
+ // add synthetics
+ synthetics get e.sym match {
+ case Some(tree) =>
+ newStats += tree
+ synthetics -= e.sym
+ case None =>
+ }
+
e = e.next
}
+ if (newStats.isEmpty) stats
+ else stats ::: (newStats.toList map typedStat)
}
val result = List.mapConserve(stats)(typedStat)
- if (!phase.erasedTypes) checkNoDoubleDefs(result)
- result
+ if (phase.erasedTypes) result
+ else checkNoDoubleDefsAndAddSynthetics(result)
}
def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree =
@@ -1571,13 +1604,11 @@ trait Typers { self: Analyzer =>
val argtypes = args map (arg => AllClass.tpe)
val pre = fun.symbol.tpe.prefix
var sym = fun.symbol filter { alt =>
- isApplicableSafe(context.undetparams, pre.memberType(alt), argtypes, pt)
+ isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
}
if (sym hasFlag OVERLOADED) {
// eliminate functions that would result from tupling transforms
- val sym1 = sym filter { alt =>
- formalTypes(alt.tpe.paramTypes, argtypes.length).length == argtypes.length
- }
+ val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length))
if (sym1 != NoSymbol) sym = sym1
}
if (sym != NoSymbol)
@@ -1922,6 +1953,7 @@ trait Typers { self: Analyzer =>
trackSetInfo(quantified setFlag EXISTENTIAL)(bound.cloneInfo(quantified))
}
val typeParamTypes = typeParams map (_.tpe) // don't trackSetInfo here, since type already set!
+ //println("ex trans "+rawSyms+" . "+tp+" "+typeParamTypes+" "+(typeParams map (_.info)))//DEBUG
for (tparam <- typeParams) tparam.setInfo(tparam.info.subst(rawSyms, typeParamTypes))
(typeParams, tp.subst(rawSyms, typeParamTypes))
}
@@ -2237,7 +2269,9 @@ trait Typers { self: Analyzer =>
} else {
if (!lhs1.tpe.isError) {
//println(lhs1+" = "+rhs)//DEBUG
- error(tree.pos, "assignment to non-variable ")
+ error(tree.pos, "assignment to "+
+ (if ((varsym ne null) && varsym.isValue) "immutable value"
+ else "non variable"))
}
setError(tree)
}
@@ -2629,7 +2663,6 @@ trait Typers { self: Analyzer =>
case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name)
}
val result = stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt)
- if (sym.isCaseFactory && !phase.erasedTypes) checkStable(qual)
if (!global.phase.erasedTypes && settings.Xchecknull.value &&
!sym.isConstructor &&
!(qual.tpe <:< NotNullClass.tpe) && !qual.tpe.isNotNull)
@@ -2676,14 +2709,13 @@ trait Typers { self: Analyzer =>
var defSym: Symbol = tree.symbol // the directly found symbol
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
var qual: Tree = EmptyTree // the qualififier tree if transformed tree is a select
- // if we are in a constructor of a pattern, ignore all methods
- // which are not case factories (note if we don't do that
+
+ // if we are in a constructor of a pattern, ignore all definitions
+ // which are methods (note: if we don't do that
// case x :: xs in class List would return the :: method).
def qualifies(sym: Symbol): Boolean =
sym.exists &&
- ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) ||
- !sym.isSourceMethod || sym.isCaseFactory)
-
+ ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod)
if (defSym == NoSymbol) {
var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope
@@ -2795,8 +2827,7 @@ trait Typers { self: Analyzer =>
if (inIDE) {
Ident(defSym.name) setType tree1.tpe setSymbol defSym setPos tree.pos
} else tree1
- }
- else {
+ } else {
var tree1 = if (qual == EmptyTree) tree
else atPos(tree.pos)(Select(qual, name))
// atPos necessary because qualifier might come from startContext
@@ -3380,7 +3411,7 @@ trait Typers { self: Analyzer =>
def improves(info1: ImplicitInfo, info2: ImplicitInfo) =
(info2 == NoImplicitInfo) ||
(info1 != NoImplicitInfo) &&
- isStrictlyBetterExpr(info1.tpe, info2.tpe)
+ isStrictlyMoreSpecific(info1.tpe, info2.tpe)
val shadowed = new HashSet[Name](8)
def isApplicable(info: ImplicitInfo): Boolean =
!containsError(info.tpe) &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 98c6935953..c0be7a9454 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -6,6 +6,8 @@
package scala.tools.nsc.typechecker
+import symtab.Flags._
+
/*
* @author Martin Odersky
* @version 1.0
@@ -14,6 +16,7 @@ trait Unapplies { self: Analyzer =>
import global._
import definitions._
+ import posAssigner.atPos
/** returns type list for return type of the extraction */
def unapplyTypeList(ufn: Symbol, ufntpe: Type) = {
@@ -79,7 +82,6 @@ trait Unapplies { self: Analyzer =>
else
productType({val es = elems; if(useWildCards) elems map { x => WildcardType} else elems})
*/
-
def unapplyReturnTypeExpected(argsLength: Int) = argsLength match {
case 0 => BooleanClass.tpe
case 1 => optionType(WildcardType)
@@ -92,4 +94,88 @@ trait Unapplies { self: Analyzer =>
if (unapp == NoSymbol) unapp = tp.member(nme.unapplySeq)
unapp
}
+
+ private def copyUntyped[T <: Tree](tree: T): T = {
+ val tree1 = tree.duplicate
+ UnTyper.traverse(tree1)
+ tree1
+ }
+
+ private def classType(cdef: ClassDef, tparams: List[TypeDef]): Tree = {
+ val tycon = gen.mkAttributedRef(cdef.symbol)
+ if (tparams.isEmpty) tycon else AppliedTypeTree(tycon, tparams map (x => Ident(x.name)))
+ }
+
+ private def constrParams(cdef: ClassDef): List[List[ValDef]] = {
+ val constr = treeInfo.firstConstructor(cdef.impl.body)
+ (constr: @unchecked) match {
+ case DefDef(_, _, _, vparamss, _, _) => vparamss map (_ map copyUntyped[ValDef])
+ }
+ }
+
+ /** The return value of an unapply method of a case class C[Ts]
+ * @param param The name of the parameter of the unapply method, assumed to be of type C[Ts]
+ * @param caseclazz The case class C[Ts]
+ */
+ private def caseClassUnapplyReturnValue(param: Name, caseclazz: Symbol) = {
+ def caseFieldAccessorValue(selector: Symbol) = Select(Ident(param), selector)
+ val accessors = caseclazz.caseFieldAccessors
+ if (accessors.isEmpty) Literal(true)
+ else if (accessors.tail.isEmpty) caseFieldAccessorValue(accessors.head)
+ else Apply(gen.scalaDot(newTermName( "Tuple" + accessors.length)), accessors map caseFieldAccessorValue)
+ }
+
+ /** The module corresponding to a case class; without any member definitions
+ */
+ def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {
+ var parents = List(gen.scalaScalaObjectConstr)
+ if (cdef.tparams.isEmpty && constrParams(cdef).length == 1)
+ parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),
+ Ident(cdef.name)) :: parents
+ ModuleDef(
+ Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin),
+ cdef.name.toTermName,
+ Template(parents, emptyValDef, Modifiers(0), List(), List(List()), List()))
+ }
+
+ /** The apply method corresponding to a case class
+ */
+ def caseModuleApplyMeth(cdef: ClassDef): DefDef = {
+ val tparams = cdef.tparams map copyUntyped[TypeDef]
+ def paramToArg(param: ValDef) = {
+ val id = Ident(param.name)
+ val RP = nme.REPEATED_PARAM_CLASS_NAME.toTypeName
+ param.tpt match {
+ case AppliedTypeTree(Select(_, RP), _) => Typed(id, Ident(nme.WILDCARD_STAR.toTypeName))
+ case _ =>id
+ }
+ }
+ val cparams = constrParams(cdef)
+ atPos(cdef.pos) {
+ DefDef(
+ Modifiers(SYNTHETIC | CASE),
+ nme.apply,
+ tparams,
+ cparams,
+ classType(cdef, tparams),
+ New(classType(cdef, tparams), cparams map (_ map paramToArg)))
+ }
+ }
+
+ /** The unapply method corresponding to a case class
+ */
+ def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = {
+ val tparams = cdef.tparams map copyUntyped[TypeDef]
+ val unapplyParamName = newTermName("x$0")
+ atPos(cdef.pos) {
+ DefDef(
+ Modifiers(SYNTHETIC | CASE),
+ nme.unapply,
+ tparams,
+ List(List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName,
+ classType(cdef, tparams), EmptyTree))),
+ TypeTree(),
+ caseClassUnapplyReturnValue(unapplyParamName, cdef.symbol))
+ }
+ }
}
diff --git a/src/library/scala/collection/jcl/SortedSet.scala b/src/library/scala/collection/jcl/SortedSet.scala
index d1317096ad..0e59eb5c43 100644
--- a/src/library/scala/collection/jcl/SortedSet.scala
+++ b/src/library/scala/collection/jcl/SortedSet.scala
@@ -9,6 +9,7 @@
// $Id$
package scala.collection.jcl;
+import Predef._
object SortedSet {
trait Projection[A] extends Set.Projection[A] with SortedSet[A] {
@@ -49,7 +50,8 @@ trait SortedSet[A] extends scala.collection.SortedSet[A] with jcl.Set[A] with So
override def has(a : A) : Boolean = SortedSet.this.has(a)
}
- protected class Filter(p : A => Boolean) extends super.Filter(p) with SortedSet.Projection[A] {
+ protected class Filter(pp : A => Boolean) extends super.Filter(pp) with SortedSet.Projection[A] {
+ override def p(a : A) = pp(a)
def compare(a0 : A, a1 : A) : Int = SortedSet.this.compare(a0, a1);
override def filter(p0 : A => Boolean) = SortedSet.this.projection.filter(k => p(k) && p0(k));
}