From 16702363dbf3a305b9a7f04c04df18f58f2a3b15 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Thu, 5 Jul 2012 17:19:51 +0200 Subject: SI-5974 make collection.convert.Wrappers serializable --- test/files/run/t5974.check | 1 + test/files/run/t5974.scala | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 test/files/run/t5974.check create mode 100644 test/files/run/t5974.scala (limited to 'test/files/run') diff --git a/test/files/run/t5974.check b/test/files/run/t5974.check new file mode 100644 index 0000000000..9766475a41 --- /dev/null +++ b/test/files/run/t5974.check @@ -0,0 +1 @@ +ok diff --git a/test/files/run/t5974.scala b/test/files/run/t5974.scala new file mode 100644 index 0000000000..5b99e9f721 --- /dev/null +++ b/test/files/run/t5974.scala @@ -0,0 +1,10 @@ +object Test extends App { + import scala.collection.JavaConverters._ + + def ser(a: AnyRef) = + (new java.io.ObjectOutputStream(new java.io.ByteArrayOutputStream())).writeObject(a) + + val l = java.util.Arrays.asList("pigdog").asScala + ser(l) + println("ok") +} -- cgit v1.2.3 From 58c053c454dd0cb1146434b97380e4910b6060d7 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 6 Jul 2012 14:05:44 +0200 Subject: stringinterpolation macro test files This commit adds test files neg: checks the error messages generated by the compiler run: checks the macro implementation features --- test/files/neg/stringinterpolation_macro-neg.check | 70 ++++++++++++++ test/files/neg/stringinterpolation_macro-neg.scala | 31 +++++++ test/files/run/stringinterpolation_macro-run.check | 62 +++++++++++++ test/files/run/stringinterpolation_macro-run.scala | 103 +++++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 test/files/neg/stringinterpolation_macro-neg.check create mode 100644 test/files/neg/stringinterpolation_macro-neg.scala create mode 100644 test/files/run/stringinterpolation_macro-run.check create mode 100644 test/files/run/stringinterpolation_macro-run.scala (limited to 'test/files/run') diff --git a/test/files/neg/stringinterpolation_macro-neg.check b/test/files/neg/stringinterpolation_macro-neg.check new file mode 100644 index 0000000000..8986b899a3 --- /dev/null +++ b/test/files/neg/stringinterpolation_macro-neg.check @@ -0,0 +1,70 @@ +stringinterpolation_macro-neg.scala:8: error: too few parts + new StringContext().f() + ^ +stringinterpolation_macro-neg.scala:9: error: too few arguments for interpolated string + new StringContext("", " is ", "%2d years old").f(s) + ^ +stringinterpolation_macro-neg.scala:10: error: too many arguments for interpolated string + new StringContext("", " is ", "%2d years old").f(s, d, d) + ^ +stringinterpolation_macro-neg.scala:11: error: too few arguments for interpolated string + new StringContext("", "").f() + ^ +stringinterpolation_macro-neg.scala:14: error: type mismatch; + found : String + required: Boolean + f"$s%b" + ^ +stringinterpolation_macro-neg.scala:15: error: type mismatch; + found : String + required: Char + f"$s%c" + ^ +stringinterpolation_macro-neg.scala:16: error: type mismatch; + found : Double + required: Char + f"$f%c" + ^ +stringinterpolation_macro-neg.scala:17: error: type mismatch; + found : String + required: Int + f"$s%x" + ^ +stringinterpolation_macro-neg.scala:18: error: type mismatch; + found : Boolean + required: Int + f"$b%d" + ^ +stringinterpolation_macro-neg.scala:19: error: type mismatch; + found : String + required: Int + f"$s%d" + ^ +stringinterpolation_macro-neg.scala:20: error: type mismatch; + found : Double + required: Int + f"$f%o" + ^ +stringinterpolation_macro-neg.scala:21: error: type mismatch; + found : String + required: Double + f"$s%e" + ^ +stringinterpolation_macro-neg.scala:22: error: type mismatch; + found : Boolean + required: Double + f"$b%f" + ^ +stringinterpolation_macro-neg.scala:27: error: type mismatch; + found : String + required: Int +Note that implicit conversions are not applicable because they are ambiguous: + both value strToInt2 of type String => Int + and value strToInt1 of type String => Int + are possible conversion functions from String to Int + f"$s%d" + ^ +stringinterpolation_macro-neg.scala:30: error: illegal conversion character + f"$s%i" + ^ +15 errors found diff --git a/test/files/neg/stringinterpolation_macro-neg.scala b/test/files/neg/stringinterpolation_macro-neg.scala new file mode 100644 index 0000000000..ac9d97d678 --- /dev/null +++ b/test/files/neg/stringinterpolation_macro-neg.scala @@ -0,0 +1,31 @@ +object Test extends App { + val s = "Scala" + val d = 8 + val b = false + val f = 3.14159 + + // 1) number of arguments + new StringContext().f() + new StringContext("", " is ", "%2d years old").f(s) + new StringContext("", " is ", "%2d years old").f(s, d, d) + new StringContext("", "").f() + + // 2) Interpolation mismatches + f"$s%b" + f"$s%c" + f"$f%c" + f"$s%x" + f"$b%d" + f"$s%d" + f"$f%o" + f"$s%e" + f"$b%f" + + { + implicit val strToInt1 = (s: String) => 1 + implicit val strToInt2 = (s: String) => 2 + f"$s%d" + } + + f"$s%i" +} diff --git a/test/files/run/stringinterpolation_macro-run.check b/test/files/run/stringinterpolation_macro-run.check new file mode 100644 index 0000000000..be62c5780b --- /dev/null +++ b/test/files/run/stringinterpolation_macro-run.check @@ -0,0 +1,62 @@ +false +false +true +false +true +FALSE +FALSE +TRUE +FALSE +TRUE +true +false +null +0 +80000000 +4c01926 +NULL +4C01926 +null +NULL +Scala +SCALA +5 +x +x +x +x +x +x +x +x +x +x +x +x +S +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +42 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.400000e+00 +3.000000e+00 +3.000000e+00 +05/26/12 +05/26/12 +05/26/12 +05/26/12 diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala new file mode 100644 index 0000000000..9c59c334f8 --- /dev/null +++ b/test/files/run/stringinterpolation_macro-run.scala @@ -0,0 +1,103 @@ +object Test extends App { + +// 'b' / 'B' (category: general) +// ----------------------------- +println(f"${null}%b") +println(f"${false}%b") +println(f"${true}%b") +println(f"${new java.lang.Boolean(false)}%b") +println(f"${new java.lang.Boolean(true)}%b") + +println(f"${null}%B") +println(f"${false}%B") +println(f"${true}%B") +println(f"${new java.lang.Boolean(false)}%B") +println(f"${new java.lang.Boolean(true)}%B") + +implicit val stringToBoolean = java.lang.Boolean.parseBoolean(_: String) +println(f"${"true"}%b") +println(f"${"false"}%b") + +// 'h' | 'H' (category: general) +// ----------------------------- +println(f"${null}%h") +println(f"${0.0}%h") +println(f"${-0.0}%h") +println(f"${"Scala"}%h") + +println(f"${null}%H") +println(f"${"Scala"}%H") + +// 's' | 'S' (category: general) +// ----------------------------- +println(f"${null}%s") +println(f"${null}%S") +println(f"${"Scala"}%s") +println(f"${"Scala"}%S") +println(f"${5}") + +// 'c' | 'C' (category: character) +// ------------------------------- +println(f"${120:Char}%c") +println(f"${120:Byte}%c") +println(f"${120:Short}%c") +println(f"${120:Int}%c") +println(f"${new java.lang.Character('x')}%c") +println(f"${new java.lang.Byte(120:Byte)}%c") +println(f"${new java.lang.Short(120:Short)}%c") +println(f"${new java.lang.Integer(120)}%c") + +println(f"${'x' : java.lang.Character}%c") +println(f"${(120:Byte) : java.lang.Byte}%c") +println(f"${(120:Short) : java.lang.Short}%c") +println(f"${120 : java.lang.Integer}%c") + +implicit val stringToChar = (x: String) => x(0) +println(f"${"Scala"}%c") + +// 'd' | 'o' | 'x' | 'X' (category: integral) +// ------------------------------------------ +println(f"${120:Byte}%d") +println(f"${120:Short}%d") +println(f"${120:Int}%d") +println(f"${120:Long}%d") +println(f"${new java.lang.Byte(120:Byte)}%d") +println(f"${new java.lang.Short(120:Short)}%d") +println(f"${new java.lang.Integer(120)}%d") +println(f"${new java.lang.Long(120)}%d") +println(f"${120 : java.lang.Integer}%d") +println(f"${120 : java.lang.Long}%d") +println(f"${BigInt(120)}%d") +println(f"${new java.math.BigInteger("120")}%d") + +{ + implicit val strToShort = (s: String) => java.lang.Short.parseShort(s) + println(f"${"120"}%d") + implicit val strToInt = (s: String) => 42 + println(f"${"120"}%d") +} + +// 'e' | 'E' | 'g' | 'G' | 'f' | 'a' | 'A' (category: floating point) +// ------------------------------------------------------------------ +println(f"${3.4f}%e") +println(f"${3.4}%e") +println(f"${3.4f : java.lang.Float}%e") +println(f"${3.4 : java.lang.Double}%e") +println(f"${BigDecimal(3.4)}%e") +println(f"${new java.math.BigDecimal(3.4)}%e") +println(f"${3}%e") +println(f"${3L}%e") + +// 't' | 'T' (category: date/time) +// ------------------------------- +import java.util.Calendar +import java.util.Locale +val c = Calendar.getInstance(Locale.US) +c.set(2012, Calendar.MAY, 26) +println(f"${c}%TD") +println(f"${c.getTime}%TD") +println(f"${c.getTime.getTime}%TD") + +implicit val strToDate = (x: String) => c +println(f"""${"1234"}%TD""") +} -- cgit v1.2.3 From a3fe989833cc482dbae04a2e2f822a74cad67a36 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 6 Jul 2012 21:13:44 +0400 Subject: SI-6036 yet again makes sense of magic symbols --- .../scala/reflect/makro/runtime/Mirrors.scala | 9 ++- .../scala/tools/nsc/typechecker/Typers.scala | 4 +- .../scala/reflect/internal/BuildUtils.scala | 2 +- .../scala/reflect/internal/Definitions.scala | 69 +++++++++++----------- src/reflect/scala/reflect/internal/Mirrors.scala | 4 +- .../reflect/internal/pickling/UnPickler.scala | 6 +- .../scala/reflect/runtime/JavaMirrors.scala | 21 ++++--- test/files/run/reflection-magicsymbols.check | 22 +++++++ test/files/run/reflection-magicsymbols.scala | 11 ++++ 9 files changed, 92 insertions(+), 56 deletions(-) create mode 100644 test/files/run/reflection-magicsymbols.check create mode 100644 test/files/run/reflection-magicsymbols.scala (limited to 'test/files/run') diff --git a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala index 79fa07fdb4..ec970ee696 100644 --- a/src/compiler/scala/reflect/makro/runtime/Mirrors.scala +++ b/src/compiler/scala/reflect/makro/runtime/Mirrors.scala @@ -24,11 +24,14 @@ trait Mirrors { else NoSymbol } + private lazy val libraryClasspathLoader: ClassLoader = { + val classpath = platform.classPath.asURLs + ScalaClassLoader.fromURLs(classpath) + } + private def isJavaClass(path: String): Boolean = try { - val classpath = platform.classPath.asURLs - var classLoader = ScalaClassLoader.fromURLs(classpath) - Class.forName(path, true, classLoader) + Class.forName(path, true, libraryClasspathLoader) true } catch { case (_: ClassNotFoundException) | (_: NoClassDefFoundError) | (_: IncompatibleClassChangeError) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 018daf4568..42672c1d3b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4431,7 +4431,7 @@ trait Typers extends Modes with Adaptations with Tags { if (!qual.tpe.widen.isErroneous) { if ((mode & QUALmode) != 0) { - val lastTry = missingHook(qual.tpe.typeSymbol, name) + val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name) if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt) } NotAMemberError(tree, qual, name) @@ -4650,7 +4650,7 @@ trait Typers extends Modes with Adaptations with Tags { log("Allowing empty package member " + name + " due to settings.") else { if ((mode & QUALmode) != 0) { - val lastTry = missingHook(rootMirror.RootClass, name) + val lastTry = rootMirror.missingHook(rootMirror.RootClass, name) if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt) } if (settings.debug.value) { diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 0bf5aa4b69..ad59605760 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -20,7 +20,7 @@ trait BuildUtils extends base.BuildUtils { self: SymbolTable => val result = owner.info decl name if (result ne NoSymbol) result else - mirrorThatLoaded(owner).tryMissingHooks(owner, name) orElse + mirrorThatLoaded(owner).missingHook(owner, name) orElse MissingRequirementError.notFound("%s %s in %s".format(if (name.isTermName) "term" else "type", name, owner.fullName)) } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 7891433b4f..0b592be454 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1125,6 +1125,39 @@ trait Definitions extends api.StandardDefinitions { /** Is symbol a phantom class for which no runtime representation exists? */ lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) + lazy val magicSymbols = List( + AnnotationDefaultAttr, // #2264 + RepeatedParamClass, + JavaRepeatedParamClass, + ByNameParamClass, + AnyClass, + AnyRefClass, + AnyValClass, + NullClass, + NothingClass, + SingletonClass, + EqualsPatternClass, + Any_==, + Any_!=, + Any_equals, + Any_hashCode, + Any_toString, + Any_getClass, + Any_isInstanceOf, + Any_asInstanceOf, + Any_##, + Object_eq, + Object_ne, + Object_==, + Object_!=, + Object_##, + Object_synchronized, + Object_isInstanceOf, + Object_asInstanceOf, + String_+, + ComparableClass, + JavaSerializableClass + ) /** Is the symbol that of a parent which is added during parsing? */ lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass @@ -1188,41 +1221,7 @@ trait Definitions extends api.StandardDefinitions { def init() { if (isInitialized) return - - val forced = List( // force initialization of every symbol that is entered as a side effect - AnnotationDefaultAttr, // #2264 - RepeatedParamClass, - JavaRepeatedParamClass, - ByNameParamClass, - AnyClass, - AnyRefClass, - AnyValClass, - NullClass, - NothingClass, - SingletonClass, - EqualsPatternClass, - Any_==, - Any_!=, - Any_equals, - Any_hashCode, - Any_toString, - Any_getClass, - Any_isInstanceOf, - Any_asInstanceOf, - Any_##, - Object_eq, - Object_ne, - Object_==, - Object_!=, - Object_##, - Object_synchronized, - Object_isInstanceOf, - Object_asInstanceOf, - String_+, - ComparableClass, - JavaSerializableClass - ) - + val forced = magicSymbols // force initialization of every symbol that is entered as a side effect isInitialized = true } //init diff --git a/src/reflect/scala/reflect/internal/Mirrors.scala b/src/reflect/scala/reflect/internal/Mirrors.scala index dedfd41e83..210af661ee 100644 --- a/src/reflect/scala/reflect/internal/Mirrors.scala +++ b/src/reflect/scala/reflect/internal/Mirrors.scala @@ -41,7 +41,7 @@ trait Mirrors extends api.Mirrors { if (result != NoSymbol) result else { if (settings.debug.value) { log(sym.info); log(sym.info.members) }//debug - tryMissingHooks(owner, name) orElse { + thisMirror.missingHook(owner, name) orElse { MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror) } } @@ -51,7 +51,7 @@ trait Mirrors extends api.Mirrors { protected def symbolTableMissingHook(owner: Symbol, name: Name): Symbol = self.missingHook(owner, name) - private[reflect] def tryMissingHooks(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name) + private[scala] def missingHook(owner: Symbol, name: Name): Symbol = mirrorMissingHook(owner, name) orElse symbolTableMissingHook(owner, name) /** If you're looking for a class, pass a type name. * If a module, a term name. diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 757163a074..4d8e932862 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -818,7 +818,7 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) protected def errorMissingRequirement(name: Name, owner: Symbol): Symbol = - missingHook(owner, name) orElse MissingRequirementError.signal( + mirrorThatLoaded(owner).missingHook(owner, name) orElse MissingRequirementError.signal( s"bad reference while unpickling $filename: ${name.longString} not found in ${owner.tpe.widen}" ) @@ -832,8 +832,10 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { * Similar in intent to what SymbolLoader does (but here we don't have access to * error reporting, so we rely on the typechecker to report the error). */ - def toTypeError(e: MissingRequirementError) = + def toTypeError(e: MissingRequirementError) = { + // e.printStackTrace() new TypeError(e.msg) + } /** A lazy type which when completed returns type at index `i`. */ private class LazyTypeRef(i: Int) extends LazyType { diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 41955170bd..eae6a3b297 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -999,10 +999,10 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym mirrors(rootToLoader getOrElseUpdate(root, findLoader)).get.get } - private def byName(sym: Symbol): (Name, Symbol) = sym.name -> sym - - private lazy val phantomTypes: Map[Name, Symbol] = - Map(byName(definitions.AnyRefClass)) ++ (definitions.isPhantomClass map byName) + private lazy val magicSymbols: Map[(String, Name), Symbol] = { + def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym + Map() ++ (definitions.magicSymbols filter (_.isClass) map mapEntry) + } /** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package * ., otherwise return NoSymbol. @@ -1020,13 +1020,12 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym if (name.isTermName && !owner.isEmptyPackageClass) return mirror.makeScalaPackage( if (owner.isRootSymbol) name.toString else owner.fullName+"."+name) - if (owner.name.toTermName == nme.scala_ && owner.owner.isRoot) - phantomTypes get name match { - case Some(tsym) => - owner.info.decls enter tsym - return tsym - case None => - } + magicSymbols get (owner.fullName, name) match { + case Some(tsym) => + owner.info.decls enter tsym + return tsym + case None => + } } info("*** missing: "+name+"/"+name.isTermName+"/"+owner+"/"+owner.hasPackageFlag+"/"+owner.info.decls.getClass) super.missingHook(owner, name) diff --git a/test/files/run/reflection-magicsymbols.check b/test/files/run/reflection-magicsymbols.check new file mode 100644 index 0000000000..2600847d99 --- /dev/null +++ b/test/files/run/reflection-magicsymbols.check @@ -0,0 +1,22 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> import scala.reflect.runtime.universe._ +import scala.reflect.runtime.universe._ + +scala> class A { def foo(x: Int*) = 1 } +defined class A + +scala> val sig = typeOf[A] member newTermName("foo") typeSignature +warning: there were 1 feature warnings; re-run with -feature for details +sig: reflect.runtime.universe.Type = (x: )scala.Int + +scala> val x = sig.asInstanceOf[MethodType].params.head +x: reflect.runtime.universe.Symbol = value x + +scala> println(x.typeSignature) +scala.Int* + +scala> diff --git a/test/files/run/reflection-magicsymbols.scala b/test/files/run/reflection-magicsymbols.scala new file mode 100644 index 0000000000..a40845d6ac --- /dev/null +++ b/test/files/run/reflection-magicsymbols.scala @@ -0,0 +1,11 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.reflect.runtime.universe._ + |class A { def foo(x: Int*) = 1 } + |val sig = typeOf[A] member newTermName("foo") typeSignature + |val x = sig.asInstanceOf[MethodType].params.head + |println(x.typeSignature) + |""".stripMargin +} -- cgit v1.2.3 From f2dbe673756302d5f5824fd8d0e6e3b3eb45a57b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 6 Jul 2012 19:46:14 -0700 Subject: Tweak test to pass under java 7. --- test/files/run/t3613.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/files/run') diff --git a/test/files/run/t3613.scala b/test/files/run/t3613.scala index c3b249571b..171a6a21aa 100644 --- a/test/files/run/t3613.scala +++ b/test/files/run/t3613.scala @@ -8,7 +8,7 @@ class Boopy { case "Boopy" => fireIntervalAdded( model, 0, 1 ) } def getSize = 0 - def getElementAt( idx: Int ) : AnyRef = "egal" + def getElementAt( idx: Int ) = ??? } } -- cgit v1.2.3 From 713ce7c5bb01ecf10633193baa66aa7161c68be7 Mon Sep 17 00:00:00 2001 From: clhodapp Date: Fri, 6 Jul 2012 07:04:50 -0500 Subject: New logic for TermSymbol.resolveOverloaded --- src/reflect/scala/reflect/api/Symbols.scala | 8 +- src/reflect/scala/reflect/internal/Symbols.scala | 323 +++++++++++++++++---- test/files/run/reflect-overload.scala | 19 -- .../run/reflect-resolveoverload-bynameparam.scala | 32 ++ .../run/reflect-resolveoverload-expected.scala | 43 +++ .../run/reflect-resolveoverload-invalid.scala | 43 +++ test/files/run/reflect-resolveoverload-named.scala | 26 ++ test/files/run/reflect-resolveoverload-targs.scala | 29 ++ .../reflect-resolveoverload-tparm-substitute.scala | 77 +++++ .../run/reflect-resolveoverload-variadic.scala | 27 ++ test/files/run/reflect-resolveoverload1.scala | 19 ++ test/files/run/reflect-resolveoverload2.scala | 40 +++ 12 files changed, 609 insertions(+), 77 deletions(-) delete mode 100644 test/files/run/reflect-overload.scala create mode 100644 test/files/run/reflect-resolveoverload-bynameparam.scala create mode 100644 test/files/run/reflect-resolveoverload-expected.scala create mode 100644 test/files/run/reflect-resolveoverload-invalid.scala create mode 100644 test/files/run/reflect-resolveoverload-named.scala create mode 100644 test/files/run/reflect-resolveoverload-targs.scala create mode 100644 test/files/run/reflect-resolveoverload-tparm-substitute.scala create mode 100644 test/files/run/reflect-resolveoverload-variadic.scala create mode 100644 test/files/run/reflect-resolveoverload1.scala create mode 100644 test/files/run/reflect-resolveoverload2.scala (limited to 'test/files/run') diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index eb9921a31a..11c7a38498 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -232,7 +232,13 @@ trait Symbols extends base.Symbols { self: Universe => /** The overloaded alternatives of this symbol */ def alternatives: List[Symbol] - def resolveOverloaded(pre: Type = NoPrefix, targs: Seq[Type] = List(), actuals: Seq[Type]): Symbol + def resolveOverloaded( + pre: Type = NoPrefix, + targs: Seq[Type] = List(), + posVargs: Seq[Type] = List(), + nameVargs: Seq[(TermName, Type)] = List(), + expected: Type = NoType + ): Symbol } /** The API of type symbols */ diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 119c3d42fd..3cb9f6ff37 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -82,71 +82,280 @@ trait Symbols extends api.Symbols { self: SymbolTable => def getAnnotations: List[AnnotationInfo] = { initialize; annotations } def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this } - private def lastElemType(ts: Seq[Type]): Type = ts.last.normalize.typeArgs.head + def resolveOverloaded( + pre: Type, + targs: Seq[Type], + posVargTypes: Seq[Type], + nameVargTypes: Seq[(TermName, Type)], + expected: Type + ): Symbol = { + + // Begin Correlation Helpers + + def isCompatible(tp: Type, pt: Type): Boolean = { + def isCompatibleByName(tp: Type, pt: Type): Boolean = pt match { + case TypeRef(_, ByNameParamClass, List(res)) if !definitions.isByNameParamType(tp) => + isCompatible(tp, res) + case _ => + false + } + (tp <:< pt) || isCompatibleByName(tp, pt) + } - private def formalTypes(formals: List[Type], nargs: Int): List[Type] = { - val formals1 = formals mapConserve { - case TypeRef(_, ByNameParamClass, List(arg)) => arg - case formal => formal + def signatureAsSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = { + (substituteTypeParams(method1), substituteTypeParams(method2)) match { + case (NullaryMethodType(r1), NullaryMethodType(r2)) => + r1 <:< r2 + case (NullaryMethodType(_), MethodType(_, _)) => + true + case (MethodType(_, _), NullaryMethodType(_)) => + false + case (MethodType(p1, _), MethodType(p2, _)) => + val len = p1.length max p2.length + val sub = extend(p1 map (_.typeSignature), len) + val sup = extend(p2 map (_.typeSignature), len) + (sub corresponds sup)(isCompatible) + } } - if (isVarArgTypes(formals1)) { - val ft = lastElemType(formals) - formals1.init ::: List.fill(nargs - (formals1.length - 1))(ft) - } else formals1 - } - - def resolveOverloaded(pre: Type, targs: Seq[Type], actuals: Seq[Type]): Symbol = { - def firstParams(tpe: Type): (List[Symbol], List[Type]) = tpe match { - case PolyType(tparams, restpe) => - val (Nil, formals) = firstParams(restpe) - (tparams, formals) - case MethodType(params, _) => - (Nil, params map (_.tpe)) - case _ => - (Nil, Nil) + + def scopeMoreSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = { + val o1 = method1.owner.asClassSymbol + val o2 = method2.owner.asClassSymbol + val c1 = if (o1.hasFlag(Flag.MODULE)) o1.companionSymbol else o1 + val c2 = if (o2.hasFlag(Flag.MODULE)) o2.companionSymbol else o2 + c1.typeSignature <:< c2.typeSignature } - def isApplicable(alt: Symbol, targs: List[Type], actuals: Seq[Type]) = { - def isApplicableType(tparams: List[Symbol], tpe: Type): Boolean = { - val (tparams, formals) = firstParams(pre memberType alt) - val formals1 = formalTypes(formals, actuals.length) - val actuals1 = - if (isVarArgTypes(actuals)) { - if (!isVarArgTypes(formals)) return false - actuals.init :+ lastElemType(actuals) - } else actuals - if (formals1.length != actuals1.length) return false - - if (tparams.isEmpty) return (actuals1 corresponds formals1)(_ <:< _) - - if (targs.length == tparams.length) - isApplicableType(List(), tpe.instantiateTypeParams(tparams, targs)) - else if (targs.nonEmpty) - false - else { - val tvars = tparams map (TypeVar(_)) - (actuals1 corresponds formals1) { (actual, formal) => - val tp1 = actual.deconst.instantiateTypeParams(tparams, tvars) - val pt1 = actual.instantiateTypeParams(tparams, tvars) - tp1 <:< pt1 - } && - solve(tvars, tparams, List.fill(tparams.length)(COVARIANT), upper = false) + + def moreSpecific(method1: MethodSymbol, method2: MethodSymbol): Boolean = { + def points(m1: MethodSymbol, m2: MethodSymbol) = { + val p1 = if (signatureAsSpecific(m1, m2)) 1 else 0 + val p2 = if (scopeMoreSpecific(m1, m2)) 1 else 0 + p1 + p2 + } + points(method1, method2) > points(method2, method1) + } + + def combineInto ( + variadic: Boolean + )( + positional: Seq[Type], + named: Seq[(TermName, Type)] + )( + target: Seq[TermName], + defaults: Map[Int, Type] + ): Option[Seq[Type]] = { + + val offset = positional.length + val unfilled = target.zipWithIndex drop offset + val canAcceptAllNameVargs = named forall { case (argName, _) => + unfilled exists (_._1 == argName) + } + + val paramNamesUnique = { + named.length == named.map(_._1).distinct.length + } + + if (canAcceptAllNameVargs && paramNamesUnique) { + + val rest = unfilled map { case (paramName, paramIndex) => + val passedIn = named.collect { + case (argName, argType) if argName == paramName => argType + }.headOption + if (passedIn isDefined) passedIn + else defaults.get(paramIndex).map(_.asInstanceOf[Type]) + } + + val rest1 = { + if (variadic && !rest.isEmpty && !rest.last.isDefined) rest.init + else rest } + + + if (rest1 forall (_.isDefined)) { + val joined = positional ++ rest1.map(_.get) + val repeatedCollapsed = { + if (variadic) { + val (normal, repeated) = joined.splitAt(target.length - 1) + if (repeated.forall(_ =:= repeated.head)) Some(normal ++ repeated.headOption) + else None + } + else Some(joined) + } + if (repeatedCollapsed.exists(_.length == target.length)) + repeatedCollapsed + else if (variadic && repeatedCollapsed.exists(_.length == target.length - 1)) + repeatedCollapsed + else None + } else None + + } else None + } + + // Begin Reflection Helpers + + // Replaces a repeated parameter type at the end of the parameter list + // with a number of non-repeated parameter types in order to pad the + // list to be nargs in length + def extend(types: Seq[Type], nargs: Int): Seq[Type] = { + if (isVarArgTypes(types)) { + val repeatedType = types.last.normalize.typeArgs.head + types.init ++ Seq.fill(nargs - (types.length - 1))(repeatedType) + } else types + } + + // Replaces by-name parameters with their result type and + // TypeRefs with the thing they reference + def unwrap(paramType: Type): Type = paramType match { + case TypeRef(_, IntClass, _) => typeOf[Int] + case TypeRef(_, LongClass, _) => typeOf[Long] + case TypeRef(_, ShortClass, _) => typeOf[Short] + case TypeRef(_, ByteClass, _) => typeOf[Byte] + case TypeRef(_, CharClass, _) => typeOf[Char] + case TypeRef(_, FloatClass, _) => typeOf[Float] + case TypeRef(_, DoubleClass, _) => typeOf[Double] + case TypeRef(_, BooleanClass, _) => typeOf[Boolean] + case TypeRef(_, UnitClass, _) => typeOf[Unit] + case TypeRef(_, NullClass, _) => typeOf[Null] + case TypeRef(_, AnyClass, _) => typeOf[Any] + case TypeRef(_, NothingClass, _) => typeOf[Nothing] + case TypeRef(_, AnyRefClass, _) => typeOf[AnyRef] + case TypeRef(_, ByNameParamClass, List(resultType)) => unwrap(resultType) + case t: Type => t + } + + // Gives the names of the parameters to a method + def paramNames(signature: Type): Seq[TermName] = signature match { + case PolyType(_, resultType) => paramNames(resultType) + case MethodType(params, _) => params.map(_.name.asInstanceOf[TermName]) + case NullaryMethodType(_) => Seq.empty + } + + def valParams(signature: Type): Seq[TermSymbol] = signature match { + case PolyType(_, resultType) => valParams(resultType) + case MethodType(params, _) => params.map(_.asTermSymbol) + case NullaryMethodType(_) => Seq.empty + } + + // Returns a map from parameter index to default argument type + def defaultTypes(method: MethodSymbol): Map[Int, Type] = { + val typeSig = substituteTypeParams(method) + val owner = method.owner + valParams(typeSig).zipWithIndex.filter(_._1.hasFlag(Flag.DEFAULTPARAM)).map { case(_, index) => + val name = nme.defaultGetterName(method.name.decodedName, index + 1) + val default = owner.asType member name + index -> default.typeSignature.asInstanceOf[NullaryMethodType].resultType + }.toMap + } + + // True if any of method's parameters have default values. False otherwise. + def usesDefault(method: MethodSymbol): Boolean = valParams(method.typeSignature) drop(posVargTypes).length exists { param => + (param hasFlag Flag.DEFAULTPARAM) && nameVargTypes.forall { case (argName, _) => + param.name != argName + } + } + + // The number of type parameters that the method takes + def numTypeParams(x: MethodSymbol): Int = { + x.typeSignature.typeParams.length + } + + def substituteTypeParams(m: MethodSymbol): Type = { + (pre memberType m) match { + case m: MethodType => m + case n: NullaryMethodType => n + case PolyType(tparams, rest) => rest.substituteTypes(tparams, targs.toList) } - isApplicableType(List(), pre.memberType(alt)) } - def isAsGood(alt1: Symbol, alt2: Symbol): Boolean = { - alt1 == alt2 || - alt2 == NoSymbol || { - val (tparams, formals) = firstParams(pre memberType alt1) - isApplicable(alt2, tparams map (_.tpe), formals) + + // Begin Selection Helpers + + def select( + alternatives: Seq[MethodSymbol], + filters: Seq[Seq[MethodSymbol] => Seq[MethodSymbol]] + ): Seq[MethodSymbol] = + filters.foldLeft(alternatives)((a, f) => { + if (a.size > 1) f(a) else a + }) + + // Drop arguments that take the wrong number of type + // arguments. + val posTargLength: Seq[MethodSymbol] => Seq[MethodSymbol] = _.filter { alt => + numTypeParams(alt) == targs.length + } + + // Drop methods that are not applicable to the arguments + val applicable: Seq[MethodSymbol] => Seq[MethodSymbol] = _.filter { alt => + // Note: combine returns None if a is not applicable and + // None.exists(_ => true) == false + val paramTypes = + valParams(substituteTypeParams(alt)).map(p => unwrap(p.typeSignature)) + val variadic = isVarArgTypes(paramTypes) + val maybeArgTypes = + combineInto(variadic)(posVargTypes, nameVargTypes)(paramNames(alt.typeSignature), defaultTypes(alt)) + maybeArgTypes exists { argTypes => + if (isVarArgTypes(argTypes) && !isVarArgTypes(paramTypes)) false + else { + val a = argTypes + val p = extend(paramTypes, argTypes.length) + (a corresponds p)(_ <:< _) } + } } - assert(isOverloaded) - val applicables = alternatives filter (isApplicable(_, targs.toList, actuals)) - def winner(alts: List[Symbol]) = - ((NoSymbol: Symbol) /: alts)((best, alt) => if (isAsGood(alt, best)) alt else best) - val best = winner(applicables) - if (best == winner(applicables.reverse)) best else NoSymbol + + // Always prefer methods that don't need to use default + // arguments over those that do. + // e.g. when resolving foo(1), prefer def foo(x: Int) over + // def foo(x: Int, y: Int = 4) + val noDefaults: Seq[MethodSymbol] => Seq[MethodSymbol] = + _ filterNot usesDefault + + // Try to select the most specific method. If that's not possible, + // return all of the candidates (this will likely cause an error + // higher up in the call stack) + val mostSpecific: Seq[MethodSymbol] => Seq[MethodSymbol] = { alts => + val sorted = alts.sortWith(moreSpecific) + val mostSpecific = sorted.head + val agreeTest: MethodSymbol => Boolean = + moreSpecific(mostSpecific, _) + val disagreeTest: MethodSymbol => Boolean = + moreSpecific(_, mostSpecific) + if (!sorted.tail.forall(agreeTest)) { + mostSpecific +: sorted.tail.filterNot(agreeTest) + } else if (sorted.tail.exists(disagreeTest)) { + mostSpecific +: sorted.tail.filter(disagreeTest) + } else { + Seq(mostSpecific) + } + } + + def finalResult(t: Type): Type = t match { + case PolyType(_, rest) => finalResult(rest) + case MethodType(_, result) => finalResult(result) + case NullaryMethodType(result) => finalResult(result) + case t: Type => t + } + + // If a result type is given, drop alternatives that don't meet it + val resultType: Seq[MethodSymbol] => Seq[MethodSymbol] = + if (expected == NoType) identity + else _.filter { alt => + finalResult(substituteTypeParams(alt)) <:< expected + } + + def defaultFilteringOps = + Seq(posTargLength, resultType, applicable, noDefaults, mostSpecific) + + // Begin Method Proper + + + val alts = alternatives.map(_.asMethodSymbol) + + val selection = select(alts, defaultFilteringOps) + + val knownApplicable = applicable(selection) + + if (knownApplicable.size == 1) knownApplicable.head + else NoSymbol } } diff --git a/test/files/run/reflect-overload.scala b/test/files/run/reflect-overload.scala deleted file mode 100644 index 870a200813..0000000000 --- a/test/files/run/reflect-overload.scala +++ /dev/null @@ -1,19 +0,0 @@ -import scala.reflect.runtime.universe._ -import scala.reflect.runtime.{currentMirror => cm} - -object Test extends App { - - val s = "hello world" - val m = cm.reflect(s) - val sc = m.symbol - val st = sc.asType - val meth = (st member newTermName("indexOf")).asTermSymbol - val IntType = definitions.IntClass.asType - val indexOf = (meth resolveOverloaded(actuals = List(IntType))).asMethodSymbol - assert(m.reflectMethod(indexOf)('w') == 6) - assert((m.reflectMethod(indexOf)('w') match { case x: Int => x }) == 6) - - val meth2 = (st member newTermName("substring")).asTermSymbol - val substring = (meth2 resolveOverloaded(actuals = List(IntType, IntType))).asMethodSymbol - assert(m.reflectMethod(substring)(2, 6) == "llo ") -} diff --git a/test/files/run/reflect-resolveoverload-bynameparam.scala b/test/files/run/reflect-resolveoverload-bynameparam.scala new file mode 100644 index 0000000000..7fb8c82ab8 --- /dev/null +++ b/test/files/run/reflect-resolveoverload-bynameparam.scala @@ -0,0 +1,32 @@ + +class A +class B extends A + +class C { + def foo(x: => Int)(y: String) = x + def foo(x: String)(y: List[_]) = x + def foo(x: => A)(y: Array[_]) = 1 + def foo(x: A)(y: Seq[_]) = 2 + def foo(x: B)(y: Map[_, _]) = 4 +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val c = new C + val im = cm.reflect(c) + val t = u.typeOf[C] member u.newTermName("foo") asTermSymbol + val f1 = t.resolveOverloaded(posVargs = List(u.typeOf[Int])) asMethodSymbol + val f2 = t.resolveOverloaded(posVargs = List(u.typeOf[String])) asMethodSymbol + val f3 = t.resolveOverloaded(posVargs = List(u.typeOf[A])) asMethodSymbol + val f4 = t.resolveOverloaded(posVargs = List(u.typeOf[B])) asMethodSymbol + val m1 = im.reflectMethod(f1) + val m2 = im.reflectMethod(f2) + val m3 = im.reflectMethod(f3) + val m4 = im.reflectMethod(f4) + assert(m1(() => 1, null) == c.foo(1)(null)) + assert(m2("a", null) == c.foo("a")(null)) + assert(m3(new A, null) == c.foo(new A)(null)) + assert(m4(new B, null) == c.foo(new B)(null)) +} + diff --git a/test/files/run/reflect-resolveoverload-expected.scala b/test/files/run/reflect-resolveoverload-expected.scala new file mode 100644 index 0000000000..1378090309 --- /dev/null +++ b/test/files/run/reflect-resolveoverload-expected.scala @@ -0,0 +1,43 @@ + +class A { + override def equals(x: Any) = { + x.isInstanceOf[A] && !x.isInstanceOf[B] + } +} +class B extends A { + override def equals(x: Any) = { + x.isInstanceOf[B] + } +} + +class C { + def a(x: String) = 1 + def a(x: Array[_]) = "a" + def b(x: String) = new A + def b(x: Array[_]) = new B + def c(x: String) = new B + def c(x: Array[_]) = "a" +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val c = new C + val im = cm.reflect(c) + def invoke(s: String, expectedType: u.Type, expectedResult: Any) { + val ol = (u.typeOf[C] member u.newTermName(s)).asTermSymbol + val methodSym = ol.resolveOverloaded(posVargs = List(u.typeOf[Null]), expected = expectedType).asMethodSymbol + val sig = methodSym.typeSignature.asInstanceOf[u.MethodType] + val method = im.reflectMethod(methodSym) + assert(method(null) == expectedResult) + } + + invoke("a", u.typeOf[Int], c.a(null): Int) + invoke("a", u.typeOf[String], c.a(null): String) + invoke("b", u.typeOf[B], c.b(null): B) + invoke("c", u.typeOf[A], c.c(null): A) + invoke("c", u.typeOf[A], c.c(null): A) + invoke("c", u.typeOf[B], c.c(null): B) + invoke("c", u.typeOf[String], c.c(null): String) + +} diff --git a/test/files/run/reflect-resolveoverload-invalid.scala b/test/files/run/reflect-resolveoverload-invalid.scala new file mode 100644 index 0000000000..def28ccbb4 --- /dev/null +++ b/test/files/run/reflect-resolveoverload-invalid.scala @@ -0,0 +1,43 @@ + +class A +class B extends A + +class C { + def a(x: Int) = 1 + def a(x: String) = 2 + def b(x: B) = 3 + def c(x: A, y: B) = 4 + def c(x: B, y: A) = 5 + def d[T](x: Int) = 6 + def d(x: String) = 7 + def e(x: A) = 8 + def e(x: =>B) = 9 +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + + val x = new C + val t = u.typeOf[C] + + val a = t member u.newTermName("a") asTermSymbol + val b = t member u.newTermName("b") asTermSymbol + val c = t member u.newTermName("c") asTermSymbol + val d = t member u.newTermName("d") asTermSymbol + val e = t member u.newTermName("e") asTermSymbol + + val n1 = a.resolveOverloaded(posVargs = List(u.typeOf[Char])) + val n2 = b.resolveOverloaded(posVargs = List(u.typeOf[A])) + val n3 = c.resolveOverloaded(posVargs = List(u.typeOf[B], u.typeOf[B])) + val n4 = d.resolveOverloaded(targs = List(u.typeOf[Int])) + val n5 = d.resolveOverloaded() + val n6 = e.resolveOverloaded(posVargs = List(u.typeOf[B])) + + assert(n1 == u.NoSymbol) + assert(n2 == u.NoSymbol) + assert(n3 == u.NoSymbol) + assert(n4 == u.NoSymbol) + assert(n5 == u.NoSymbol) + assert(n6 == u.NoSymbol) +} diff --git a/test/files/run/reflect-resolveoverload-named.scala b/test/files/run/reflect-resolveoverload-named.scala new file mode 100644 index 0000000000..017ec85c0d --- /dev/null +++ b/test/files/run/reflect-resolveoverload-named.scala @@ -0,0 +1,26 @@ + +class A { + def foo(x: String, y: Int) = 1 + def foo(x: Int, y: String) = 2 +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val a = new A + val im = cm.reflect(a) + val tpe = u.typeOf[A] + val overloaded = tpe member u.newTermName("foo") asTermSymbol + val ms1 = + overloaded resolveOverloaded(nameVargs = Seq((u.newTermName("x"), u.typeOf[String]), (u.newTermName("y"), u.typeOf[Int]))) + val ms2 = + overloaded resolveOverloaded(nameVargs = Seq((u.newTermName("y"), u.typeOf[Int]), (u.newTermName("x"), u.typeOf[String]))) + val ms3 = + overloaded resolveOverloaded(nameVargs = Seq((u.newTermName("x"), u.typeOf[Int]), (u.newTermName("y"), u.typeOf[String]))) + val ms4 = + overloaded resolveOverloaded(nameVargs = Seq((u.newTermName("y"), u.typeOf[String]), (u.newTermName("x"), u.typeOf[Int]))) + assert(im.reflectMethod(ms1 asMethodSymbol)("A", 1) == 1) + assert(im.reflectMethod(ms2 asMethodSymbol)("A", 1) == 1) + assert(im.reflectMethod(ms3 asMethodSymbol)(1, "A") == 2) + assert(im.reflectMethod(ms4 asMethodSymbol)(1, "A") == 2) +} diff --git a/test/files/run/reflect-resolveoverload-targs.scala b/test/files/run/reflect-resolveoverload-targs.scala new file mode 100644 index 0000000000..888b2f0c15 --- /dev/null +++ b/test/files/run/reflect-resolveoverload-targs.scala @@ -0,0 +1,29 @@ + +import reflect.runtime.{universe=>u} +import scala.reflect.runtime.{currentMirror => cm} + +class C { + def foo[T: u.TypeTag](x: String) = 1 + def foo[T: u.TypeTag, S: u.TypeTag](x: String) = 2 +} + +object Test extends App { + val c = new C + val im = cm.reflect(c) + val foo = u.typeOf[C] member u.newTermName("foo") asTermSymbol + val f1 = foo.resolveOverloaded( + targs = Seq(u.typeOf[Int]), + posVargs = Seq(u.typeOf[String]) + ) + + val f2 = foo.resolveOverloaded( + targs = Seq(u.typeOf[Int], + u.typeOf[Int]), posVargs = Seq(u.typeOf[String]) + ) + + val m1 = im.reflectMethod(f1 asMethodSymbol) + val m2 = im.reflectMethod(f2 asMethodSymbol) + + assert(m1("a", u.typeTag[Int]) == c.foo[Int]("a")) + assert(m2("a", u.typeTag[Int], u.typeTag[Int]) == c.foo[Int, Int]("a")) +} diff --git a/test/files/run/reflect-resolveoverload-tparm-substitute.scala b/test/files/run/reflect-resolveoverload-tparm-substitute.scala new file mode 100644 index 0000000000..22e7bcd40a --- /dev/null +++ b/test/files/run/reflect-resolveoverload-tparm-substitute.scala @@ -0,0 +1,77 @@ + +class A +class B extends A + +class C { + def foo[T](x: T) = x + def foo(x: Int) = "a" + def foo(x: A) = x +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val c = new C + val im = cm.reflect(c) + val term = u.typeOf[C] member u.newTermName("foo") asTermSymbol + + val f1 = term.resolveOverloaded( + posVargs = List(u.typeOf[Int]), + expected = u.typeOf[String] + ) + + val f2 = term.resolveOverloaded( + targs = List(u.typeOf[String]), + posVargs = List(u.typeOf[String]), + expected = u.typeOf[String] + ) + + val f3 = term.resolveOverloaded( + posVargs = List(u.typeOf[A]), + expected = u.typeOf[A] + ) + + val f4 = term.resolveOverloaded( + targs = List(u.typeOf[A]), + posVargs = List(u.typeOf[A]), + expected = u.typeOf[A] + ) + + val f5 = term.resolveOverloaded( + targs = List(u.typeOf[B]), + posVargs = List(u.typeOf[B]), + expected = u.typeOf[B] + ) + + val f6 = term.resolveOverloaded( + targs = List(u.typeOf[B]), + posVargs = List(u.typeOf[B]), + expected = u.typeOf[A] + ) + + val f7 = term.resolveOverloaded( + targs = List(u.typeOf[A]), + posVargs = List(u.typeOf[B]), + expected = u.typeOf[A] + ) + + val m1 = im.reflectMethod(f1 asMethodSymbol) + val m2 = im.reflectMethod(f2 asMethodSymbol) + val m3 = im.reflectMethod(f3 asMethodSymbol) + val m4 = im.reflectMethod(f4 asMethodSymbol) + val m5 = im.reflectMethod(f5 asMethodSymbol) + val m6 = im.reflectMethod(f6 asMethodSymbol) + val m7 = im.reflectMethod(f7 asMethodSymbol) + + val a = new A + val b = new B + assert(m1(2) == (c.foo(2): String)) + assert(m2("xyz") == (c.foo[String]("xyz"): String)) + assert(m3(a) == (c.foo(a): A)) + assert(m4(a) == (c.foo[A](a): A)) + assert(m5(b) == (c.foo[B](b): B)) + assert(m6(b) == (c.foo[B](b): A)) + assert(m7(b) == (c.foo[A](b): A)) + + +} diff --git a/test/files/run/reflect-resolveoverload-variadic.scala b/test/files/run/reflect-resolveoverload-variadic.scala new file mode 100644 index 0000000000..8e2e15600f --- /dev/null +++ b/test/files/run/reflect-resolveoverload-variadic.scala @@ -0,0 +1,27 @@ + +class C { + def foo(x: Int*) = 1 + x.sum + def foo(x: String) = 2 +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val c = new C + val im = cm.reflect(c) + val foo = u.typeOf[C] member u.newTermName("foo") asTermSymbol + val f0 = foo.resolveOverloaded() + val f1 = foo.resolveOverloaded(posVargs = Seq(u.typeOf[Int])) + val f2 = foo.resolveOverloaded(posVargs = Seq(u.typeOf[Int], u.typeOf[Int])) + val f3 = foo.resolveOverloaded(posVargs = Seq(u.typeOf[String])) + + val m0 = im.reflectMethod(f0 asMethodSymbol) + val m1 = im.reflectMethod(f1 asMethodSymbol) + val m2 = im.reflectMethod(f2 asMethodSymbol) + val m3 = im.reflectMethod(f3 asMethodSymbol) + + assert(m0(Seq()) == c.foo()) + assert(m1(Seq(1)) == c.foo(1)) + assert(m2(Seq(4, 9)) == c.foo(4, 9)) + assert(m3("abc") == c.foo("abc")) +} diff --git a/test/files/run/reflect-resolveoverload1.scala b/test/files/run/reflect-resolveoverload1.scala new file mode 100644 index 0000000000..a859a0ec4e --- /dev/null +++ b/test/files/run/reflect-resolveoverload1.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +object Test extends App { + + val s = "hello world" + val m = cm.reflect(s) + val sc = m.symbol + val st = sc.asType + val meth = (st member newTermName("indexOf")).asTermSymbol + val IntType = definitions.IntClass.asType + val indexOf = (meth resolveOverloaded(posVargs = List(IntType))).asMethodSymbol + assert(m.reflectMethod(indexOf)('w') == 6) + assert((m.reflectMethod(indexOf)('w') match { case x: Int => x }) == 6) + + val meth2 = (st member newTermName("substring")).asTermSymbol + val substring = (meth2 resolveOverloaded(posVargs = List(IntType, IntType))).asMethodSymbol + assert(m.reflectMethod(substring)(2, 6) == "llo ") +} diff --git a/test/files/run/reflect-resolveoverload2.scala b/test/files/run/reflect-resolveoverload2.scala new file mode 100644 index 0000000000..b5f719814b --- /dev/null +++ b/test/files/run/reflect-resolveoverload2.scala @@ -0,0 +1,40 @@ +class A +class B extends A + +class C { + def a(x: Int) = 1 + def a(x: String) = 2 + //def b(x: => Int)(s: String) = 1 + //def b(x: => String)(a: Array[_]) = 2 + def c(x: A) = 1 + def c(x: B) = 2 + //def d(x: => A)(s: String) = 1 + //def d(x: => B)(a: Array[_]) = 2 + def e(x: A) = 1 + def e(x: B = new B) = 2 +} + +object Test extends App { + val cm = reflect.runtime.currentMirror + val u = cm.universe + val c = new C + val im = cm.reflect(c) + def invoke(s: String, arg: Any, argType: u.Type): Int = { + val ol = u.typeOf[C] member u.newTermName(s) asTermSymbol + val methodSym = ol.resolveOverloaded(posVargs = List(argType)) asMethodSymbol + val sig = methodSym.typeSignature.asInstanceOf[u.MethodType] + val method = im.reflectMethod(methodSym) + if (sig.resultType.kind == "MethodType") method(arg, null).asInstanceOf[Int] + else method(arg).asInstanceOf[Int] + } + assert(c.a(1) == invoke("a", 1, u.typeOf[Int])) + assert(c.a("a") == invoke("a", "a", u.typeOf[String])) + //assert(c.b(1)(null) == invoke("b", 1, u.typeOf[Int])) + //assert(c.b("a")(null) == invoke("b", "a", u.typeOf[String])) + assert(c.c(new A) == invoke("c", new A, u.typeOf[A])) + assert(c.c(new B) == invoke("c", new B, u.typeOf[B])) + //assert(c.d(new A)(null) == invoke("d", new A, u.typeOf[A])) + //assert(c.d(new B)(null) == invoke("d", new B, u.typeOf[B])) + assert(c.e(new A) == invoke("e", new A, u.typeOf[A])) + assert(c.e(new B) == invoke("e", new B, u.typeOf[B])) +} -- cgit v1.2.3