From 649289cb6882a3534ef7ac2f4a50e096af84c45f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Aug 2007 16:45:26 +0000 Subject: fixed bug1274 moved a bunch of `unapply' definitions from Definitions to a new trait, typechecker.UnApplies --- .../scala/tools/nsc/symtab/Definitions.scala | 77 ------------------ .../scala/tools/nsc/transform/UnCurry.scala | 2 +- .../scala/tools/nsc/typechecker/Analyzer.scala | 3 +- .../scala/tools/nsc/typechecker/Typers.scala | 10 +-- .../scala/tools/nsc/typechecker/UnApplies.scala | 95 ++++++++++++++++++++++ 5 files changed, 103 insertions(+), 84 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/typechecker/UnApplies.scala diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index ea94f135c9..fc3572b8f1 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -220,83 +220,6 @@ trait Definitions { case tpe => tpe }).normalize - /** returns type list for return type of the extraction */ - def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { - assert(ufn.isMethod) - //Console.println("utl "+ufntpe+" "+ufntpe.typeSymbol) - ufn.name match { - case nme.unapply => unapplyTypeListFromReturnType(ufntpe) - case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe) - case _ => throw new IllegalArgumentException("expected function symbol of extraction") - } - } - /** (the inverse of unapplyReturnTypeSeq) - * for type Boolean, returns Nil - * for type Option[T] or Some[T]: - * - returns T0...Tn if n>0 and T <: Product[T0...Tn]] - * - returns T otherwise - */ - def unapplyTypeListFromReturnType(tp1: Type): List[Type] = { // rename: unapplyTypeListFromReturnType - val tp = unapplyUnwrap(tp1) - val B = BooleanClass - val O = OptionClass - val S = SomeClass - tp.typeSymbol match { // unapplySeqResultToMethodSig - case B => Nil - case O | S => - val prod = tp.typeArgs.head - getProductArgs(prod) match { - case Some(all @ (x1::x2::xs)) => all // n >= 2 - case _ => prod::Nil // special n == 0 || n == 1 - } - case _ => throw new IllegalArgumentException(tp.typeSymbol + " in not in {boolean, option, some}") - } - } - - /** let type be the result type of the (possibly polymorphic) unapply method - * for type Option[T] or Some[T] - * -returns T0...Tn-1,Tn* if n>0 and T <: Product[T0...Tn-1,Seq[Tn]]], - * -returns R* if T = Seq[R] - */ - def unapplyTypeListFromReturnTypeSeq(tp1: Type): List[Type] = { - val tp = unapplyUnwrap(tp1) - val O = OptionClass; val S = SomeClass; tp.typeSymbol match { - case O | S => - val ts = unapplyTypeListFromReturnType(tp1) - val last1 = ts.last.baseType(SeqClass) match { - case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args) - case _ => throw new IllegalArgumentException("last not seq") - } - ts.init ::: List(last1) - case _ => throw new IllegalArgumentException(tp.typeSymbol + " in not in {option, some}") - } - } - - /** returns type of the unapply method returning T_0...T_n - * for n == 0, boolean - * for n == 1, Some[T0] - * else Some[Product[Ti]] - def unapplyReturnType(elems: List[Type], useWildCards: Boolean) = - if (elems.isEmpty) - BooleanClass.tpe - else if (elems.length == 1) - optionType(if(useWildCards) WildcardType else elems(0)) - 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) - case n => optionType(productType(List.range(0,n).map (arg => WildcardType))) - } - - /** returns unapply or unapplySeq if available */ - def unapplyMember(tp: Type): Symbol = { - var unapp = tp.member(nme.unapply) - if (unapp == NoSymbol) unapp = tp.member(nme.unapplySeq) - unapp - } /* */ val MaxFunctionArity = 9 val FunctionClass: Array[Symbol] = new Array(MaxFunctionArity + 1) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index b64dfc35d6..96ded10df1 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -421,7 +421,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { if (fn.symbol.name == nme.unapply) args else if (fn.symbol.name == nme.unapplySeq) - transformArgs(tree.pos, args, definitions.unapplyTypeListFromReturnTypeSeq(fn.tpe)) + transformArgs(tree.pos, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe)) else { assert(false,"internal error: UnApply node has wrong symbol"); null }) copy.UnApply(tree, fn1, args1) diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala index 91fcd64d5c..6d95b1a762 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala @@ -15,7 +15,8 @@ trait Analyzer extends AnyRef with Infer with Variances with EtaExpansion - with SyntheticMethods { + with SyntheticMethods + with Unapplies { val global : Global; import global._; diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c0052ccc10..c162eacc1d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -701,7 +701,7 @@ trait Typers { self: Analyzer => } tree1 } else { - val extractor = tree.symbol.filter(sym => definitions.unapplyMember(sym.tpe).exists) + val extractor = tree.symbol.filter(sym => unapplyMember(sym.tpe).exists) if (extractor != NoSymbol) { tree setSymbol extractor } else { @@ -1577,7 +1577,7 @@ trait Typers { self: Analyzer => if (forMSIL) { fun match { case Select(qual, name) => - if (isSubType(qual.tpe, definitions.DelegateClass.tpe) + if (isSubType(qual.tpe, DelegateClass.tpe) && (name == encode("+=") || name == encode("-="))) { val n = if (name == encode("+=")) nme.PLUS else nme.MINUS @@ -1631,8 +1631,8 @@ trait Typers { self: Analyzer => setError(copy.Apply(tree, fun, args)) /* --- begin unapply --- */ - case otpe if (mode & PATTERNmode) != 0 && definitions.unapplyMember(otpe).exists => - val unapp = definitions.unapplyMember(otpe) + case otpe if (mode & PATTERNmode) != 0 && unapplyMember(otpe).exists => + val unapp = unapplyMember(otpe) assert(unapp.exists, tree) val unappType = otpe.memberType(unapp) val argDummyType = pt // was unappArg @@ -2134,7 +2134,7 @@ trait Typers { self: Analyzer => case Select(qual, name) if (forMSIL && pt != WildcardType && pt != ErrorType && - isSubType(pt, definitions.DelegateClass.tpe)) => + isSubType(pt, DelegateClass.tpe)) => val scalaCaller = newScalaCaller(pt); addScalaCallerInfo(scalaCaller, expr1.symbol) val n: Name = scalaCaller.name diff --git a/src/compiler/scala/tools/nsc/typechecker/UnApplies.scala b/src/compiler/scala/tools/nsc/typechecker/UnApplies.scala new file mode 100644 index 0000000000..93e5639fc3 --- /dev/null +++ b/src/compiler/scala/tools/nsc/typechecker/UnApplies.scala @@ -0,0 +1,95 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2006 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: EtaExpansion.scala 12607 2007-08-21 14:04:16Z odersky $ + +package scala.tools.nsc.typechecker + +/* + * @author Martin Odersky + * @version 1.0 + */ +trait Unapplies { self: Analyzer => + + import global._ + import definitions._ + + /** returns type list for return type of the extraction */ + def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { + assert(ufn.isMethod) + //Console.println("utl "+ufntpe+" "+ufntpe.typeSymbol) + ufn.name match { + case nme.unapply => unapplyTypeListFromReturnType(ufntpe) + case nme.unapplySeq => unapplyTypeListFromReturnTypeSeq(ufntpe) + case _ => throw new TypeError(ufn+" is not an unapply or unapplySeq") + } + } + /** (the inverse of unapplyReturnTypeSeq) + * for type Boolean, returns Nil + * for type Option[T] or Some[T]: + * - returns T0...Tn if n>0 and T <: Product[T0...Tn]] + * - returns T otherwise + */ + def unapplyTypeListFromReturnType(tp1: Type): List[Type] = { // rename: unapplyTypeListFromReturnType + val tp = unapplyUnwrap(tp1) + val B = BooleanClass + val O = OptionClass + val S = SomeClass + tp.typeSymbol match { // unapplySeqResultToMethodSig + case B => Nil + case O | S => + val prod = tp.typeArgs.head + getProductArgs(prod) match { + case Some(all @ (x1::x2::xs)) => all // n >= 2 + case _ => prod::Nil // special n == 0 || n == 1 + } + case _ => throw new TypeError("result type "+tp+" of unapply not in {boolean, Option[_], Some[_]}") + } + } + + /** let type be the result type of the (possibly polymorphic) unapply method + * for type Option[T] or Some[T] + * -returns T0...Tn-1,Tn* if n>0 and T <: Product[T0...Tn-1,Seq[Tn]]], + * -returns R* if T = Seq[R] + */ + def unapplyTypeListFromReturnTypeSeq(tp1: Type): List[Type] = { + val tp = unapplyUnwrap(tp1) + val O = OptionClass; val S = SomeClass; tp.typeSymbol match { + case O | S => + val ts = unapplyTypeListFromReturnType(tp1) + val last1 = ts.last.baseType(SeqClass) match { + case TypeRef(pre, seqClass, args) => typeRef(pre, RepeatedParamClass, args) + case _ => throw new TypeError("last not seq") + } + ts.init ::: List(last1) + case _ => throw new TypeError("result type "+tp+" of unapply not in {Option[_], Some[_]}") + } + } + + /** returns type of the unapply method returning T_0...T_n + * for n == 0, boolean + * for n == 1, Some[T0] + * else Some[Product[Ti]] + def unapplyReturnType(elems: List[Type], useWildCards: Boolean) = + if (elems.isEmpty) + BooleanClass.tpe + else if (elems.length == 1) + optionType(if(useWildCards) WildcardType else elems(0)) + 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) + case n => optionType(productType(List.range(0,n).map (arg => WildcardType))) + } + + /** returns unapply or unapplySeq if available */ + def unapplyMember(tp: Type): Symbol = { + var unapp = tp.member(nme.unapply) + if (unapp == NoSymbol) unapp = tp.member(nme.unapplySeq) + unapp + } +} -- cgit v1.2.3