summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorBurak Emir <emir@epfl.ch>2007-01-16 12:03:38 +0000
committerBurak Emir <emir@epfl.ch>2007-01-16 12:03:38 +0000
commitf41ccda10b54ab9c1a02b8a85505b639b0bd00b1 (patch)
tree18ab8201b4330575d52d965255e80a829aa8dcbd /src/compiler
parent8bb851f21e29ab1f83776ad830922894a7b9c426 (diff)
downloadscala-f41ccda10b54ab9c1a02b8a85505b639b0bd00b1.tar.gz
scala-f41ccda10b54ab9c1a02b8a85505b639b0bd00b1.tar.bz2
scala-f41ccda10b54ab9c1a02b8a85505b639b0bd00b1.zip
some fixes for unapply:
* deals with unapply arguments that are *not* subtypes of unapply * method, handles polymorphic applies getProductArgs instead of * isProduct in PatternMatcher code generation
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternMatchers.scala60
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala34
6 files changed, 69 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 90978e58b6..4ee1ec82d0 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -131,6 +131,7 @@ class Settings(error: String => unit) {
val Xunapply = BooleanSetting("-Xunapply", "enable unapply pattern matching")
val Xplugtypes = BooleanSetting("-Xplugtypes", "parse but ignore annotations in more locations")
val Xkilloption = BooleanSetting("-Xkilloption", "optimizes option types")
+ val XprintOuterMatches = BooleanSetting("-XprintOuterMatches", "prints outer-checks caused by pattern matching ")
/** A list of all settings */
def allSettings: List[Setting] = allsettings.reverse
diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
index cda0e309f2..b4ec46bf14 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala
@@ -541,9 +541,7 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes) {
}
private def newHeader(pos: PositionType, casted: Symbol, index: Int): Header = {
- //Console.println("newHeader(pos,"+casted+","+index+")");
- //Console.println(" casted.tpe"+casted.tpe);
- //Console.println(" casted.pos "+casted.pos+" equals firstpos?"+(casted.pos == Position.FIRSTPOS));
+ //Console.println("newHeader(pos,"+casted+" (has CASE flag? "+casted.tpe.symbol.hasFlag(Flags.CASE)+") of type "+casted.tpe+" with pos "+casted.pos+"(equals FIRSTPOS? "+(casted.pos == Position.FIRSTPOS)+"),"+index+")");
val ident = typed(Ident(casted))
if (casted.pos == Position.FIRSTPOS) { // load the result of casted(i)
//Console.println("FIRSTPOS");
@@ -562,11 +560,13 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes) {
if(!casted.tpe.symbol.hasFlag(Flags.CASE)) {
//Console.println("NOT CASE");
-
- if (defs.isProductType(casted.tpe)) {
- val acc = defs.productProj(casted.tpe.typeArgs.length, index+1)
- val accTree = typed(Apply(Select(ident, acc), List())) // nsc !
- return pHeader(pos, accTree.tpe, accTree)
+ //Console.println("getProductArgs? "+defs.getProductArgs(casted.tpe));
+ defs.getProductArgs(casted.tpe) match {
+ case Some(targs) =>
+ val accSym = defs.productProj(casted.tpe.symbol, index+1)
+ val accTree = typed(Apply(Select(ident, accSym), List())) // nsc !
+ return pHeader(pos, accTree.tpe, accTree)
+ case None =>
}
/*
@@ -1264,6 +1264,8 @@ print()
case Pair(TypeRef(lprefix, _,_), TypeRef(rprefix,_,_)) if lprefix =:= rprefix =>
true
case _ =>
+ if(settings.XprintOuterMatches.value)
+ cunit.warning(node.pos, "can't be sure statically that these outers are equal:"+{left,right}.toString)
false
}
@@ -1271,7 +1273,7 @@ print()
var cond: Tree = null
// if type 2 test is same as static type, then just null test
- if(isSubType(selector.tpe,ntpe) && isSubType(ntpe, definitions.AnyRefClass.tpe)) {
+ if(isSubType(selector.tpe, ntpe) && isSubType(ntpe, definitions.AnyRefClass.tpe)) {
cond = NotNull(selector.duplicate)
nstatic = nstatic + 1
} else if(ignoreSelectorType) {
@@ -1279,27 +1281,33 @@ print()
} else {
cond = typed { gen.mkIsInstanceOf(selector.duplicate, ntpe) }
}
- // compare outer instance for patterns like foo1.Bar foo2.Bar if not statically known to match
- if(!outerAlwaysEqual(casted.tpe, selector.tpe)) {
- casted.tpe match {
- case TypeRef(prefix,_,_) if (prefix.symbol.isTerm && !prefix.symbol.isPackage) =>
- var theRef = gen.mkAttributedRef(prefix.prefix, prefix.symbol)
+ // compare outer instance for patterns like foo1.Bar foo2.Bar if not statically known to match
+ casted.tpe match {
+ case TypeRef(prefix,_,_) if
+ (prefix.symbol.isTerm && !prefix.symbol.isPackage)
+ &&(!outerAlwaysEqual(casted.tpe, selector.tpe)) =>
+ var theRef = gen.mkAttributedRef(prefix.prefix, prefix.symbol)
- // needs explicitouter treatment
- theRef = handleOuter(theRef)
+ // needs explicitouter treatment
+ theRef = handleOuter(theRef)
- val outerAcc = outerAccessor(casted.tpe.symbol)
+ val outerAcc = outerAccessor(casted.tpe.symbol)
+
+ //if(settings.XprintOuterMatches.value)
+ // cunit.warning(node.pos, "outer match "+outerAcc)
+
+ if(outerAcc != NoSymbol) { // some guys don't have outers
+ cond = And(cond,
+ Eq(Apply(Select(
+ typed(gen.mkAsInstanceOf(selector.duplicate, ntpe, true)), outerAcc),List()), theRef))
+ } else {
+ cunit.warning(node.pos, " no outer accessor for "+casted.tpe.symbol+" of type "+casted.tpe)
+ }
+ case _ =>
+ //ignore ;
+ }
- if(outerAcc != NoSymbol) { // some guys don't have outers
- cond = And(cond,
- Eq(Apply(Select(
- typed(gen.mkAsInstanceOf(selector.duplicate, ntpe, true)), outerAcc),List()), theRef))
- }
- case _ =>
- //ignore ;
- }
- }
val succ = squeezedBlock(List(ValDef(casted,
if(isSubType(selector.tpe,ntpe)) selector.duplicate else typed(gen.mkAsInstanceOf(selector.duplicate, ntpe, true)))),
toTree(node.and))
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 3203637130..b4ea587f04 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -116,8 +116,10 @@ trait Definitions requires SymbolTable {
val MaxProductArity = 22
/* <unapply> */
val ProductClass: Array[Symbol] = new Array(MaxProductArity + 1)
- def productProj(n: Int, j: Int) = getMember(ProductClass(n), "_" + j)
- def isProductType(tp: Type): Boolean = tp match {
+ def productProj(z:Symbol, j: Int): Symbol = getMember(z, nme.Product_(j))
+ def productProj(n: Int, j: Int): Symbol = productProj(ProductClass(n), j)
+ /** returns true if this type is exactly ProductN[T1,...,Tn], not some subclass */
+ def isExactProductType(tp: Type): Boolean = tp match {
case TypeRef(_, sym, elems) =>
elems.length <= MaxProductArity && sym == ProductClass(elems.length);
case _ =>
@@ -133,7 +135,7 @@ trait Definitions requires SymbolTable {
/** if tpe <: ProductN[T1,...,TN], returns Some(T1,...,TN) else None */
def getProductArgs(tpe: Type): Option[List[Type]] =
- tpe.baseClasses.find { x => definitions.isProductType(x.tpe) } match {
+ tpe.baseClasses.find { x => definitions.isExactProductType(x.tpe) } match {
case Some(p) => Some(tpe.baseType(p).typeArgs)
case _ => None
}
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index be740910ef..9757d417ee 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -207,6 +207,7 @@ trait StdNames requires SymbolTable {
val PartialFunction = newTermName("PartialFunction")
val Predef = newTermName("Predef")
val Product = newTermName("Product")
+ def Product_(i:Int) = newTermName("_" + i)
val ScalaObject = newTermName("ScalaObject")
val ScalaRunTime = newTermName("ScalaRunTime")
val Seq = newTermName("Seq")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 94dc40b230..35954ca8a7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -467,7 +467,8 @@ trait Infer requires Analyzer {
* @return ...
* @throws NoInstance
*/
- private def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type,
+ // bq: was private, but need it for unapply checking
+ def methTypeArgs(tparams: List[Symbol], formals: List[Type], restpe: Type,
argtpes: List[Type], pt: Type,
uninstantiated: ListBuffer[Symbol]): List[Type] = {
val tvars = tparams map freshVar
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 2e98c001c7..7d361a1800 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1419,12 +1419,8 @@ trait Typers requires Analyzer {
assert(unapp.exists, tree)
// this is no longer needed!
- val unappArg:Type = unapp.tpe match {
- case PolyType(_,MethodType(List(res), _)) => res
- case MethodType(List(res), _) => res
- case _ => error(fun.pos, "unapply takes too many arguments to be used as pattern"); NoType
- }
- val argDummyType = pt // was unappArg
+
+ val argDummyType = pt // was unappArg
val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY)
.setFlag(SYNTHETIC)
.setInfo(argDummyType)
@@ -1450,8 +1446,27 @@ trait Typers requires Analyzer {
}
val fun0 = Ident(fun.symbol) setPos fun.pos setType otpe // would this change when patterns are terms???
val fun1untyped = atPos(fun.pos) {
- Apply(Select(gen.mkAttributedRef(fun.tpe.prefix,fun.symbol), unapp), List(arg))
- }
+ Apply(Select(gen.mkAttributedRef(fun.tpe.prefix,fun.symbol), unapp), List(arg))
+ }
+
+ // bq: find out if argument requires instanceOf check, if yes then lie about the type
+ val oldArgType = arg.tpe
+ unapp.tpe match {
+ case MethodType(formals, restpe) =>
+ if(!isSubType(arg.tpe, formals(0))) {
+ //Console.println(" -- apply mono hack")
+ arg.tpe = AllClass.tpe // deceive typechecker, we'll insert an instanceOf check later
+ }
+ case PolyType(tparams,MethodType(fmls, res)) =>
+ try {
+ methTypeArgs(tparams, fmls, res, List(arg.tpe.deconst), WildcardType, new ListBuffer[Symbol]())
+ } catch {
+ case e => //Console.println(e.getMessage())
+ //Console.println(" -- apply poly hack")
+ arg.tpe = AllClass.tpe // deceive typechecker, we'll insert an instanceOf check later
+ }
+ }
+
//Console.println("UNAPPLY2 "+fun+"/"+fun.tpe+" "+fun1untyped+", funPt = "+funPt)
val fun1 = typed(fun1untyped, EXPRmode, funPt)
if (fun1.tpe.isErroneous) setError(tree)
@@ -1460,8 +1475,11 @@ trait Typers requires Analyzer {
val formals1 = formalTypes(formals0, args.length)
val args1 = typedArgs(args, mode, formals0, formals1)
if (!isFullyDefined(pt)) assert(false, tree+" ==> "+UnApply(fun1, args1)+", pt = "+pt)
+ // restore old type (this will never work, but just pass typechecking)
+ arg.tpe = oldArgType
UnApply(fun1, args1) setPos tree.pos setType pt
}
+
/* --- end unapply --- */
case _ =>
errorTree(tree, ""+fun+" does not take parameters")