From c800d1fec5241ed8c29e5af30465856f9b583246 Mon Sep 17 00:00:00 2001 From: Hubert Plociniczak Date: Wed, 25 Jan 2012 11:33:53 +0100 Subject: Use context for buffering errors that cannot/shouldn't be reported in the given moment (instead of throwing type errors). This avoids previous problems where we were creating fake error trees in some incorrect places like in type completers in Namers etc. Implicits relied heavily on type errors being thrown but performance should stay the same due to some explicit checks/returns. Some of the problems involved how ambiguous error messages were collected/reported because it was very random (similarly for divergent implicits). This should be more explicit now. Reduced the number of unnecessary cyclic references being thrown (apart from those in Symbols/Types which don't have a context and need to stay for now as is). Review by @paulp, @odersky. --- test/files/neg/sensitive2.check | 10 ++++++++++ test/files/neg/sensitive2.scala | 8 ++++++++ test/files/neg/t1878.check | 5 ++++- test/files/neg/t2641.check | 20 ++------------------ test/files/neg/t2918.check | 6 +++--- test/files/neg/t2918.scala | 2 +- test/files/neg/t3015.check | 7 +------ test/files/neg/t649.check | 2 +- 8 files changed, 30 insertions(+), 30 deletions(-) create mode 100644 test/files/neg/sensitive2.check create mode 100644 test/files/neg/sensitive2.scala (limited to 'test/files/neg') diff --git a/test/files/neg/sensitive2.check b/test/files/neg/sensitive2.check new file mode 100644 index 0000000000..19152fe188 --- /dev/null +++ b/test/files/neg/sensitive2.check @@ -0,0 +1,10 @@ +sensitive2.scala:6: error: type mismatch; + found : String("abc") + required: Test.Foo[_] +Note that implicit conversions are not applicable because they are ambiguous: + both method foo1 in object Test of type [A](a: A)Test.Foo[A] + and method foo2 in object Test of type (a: Any)Test.Foo[String] + are possible conversion functions from String("abc") to Test.Foo[_] + val a: Foo[_] = "abc" + ^ +one error found diff --git a/test/files/neg/sensitive2.scala b/test/files/neg/sensitive2.scala new file mode 100644 index 0000000000..92b91bef20 --- /dev/null +++ b/test/files/neg/sensitive2.scala @@ -0,0 +1,8 @@ +object Test { + class Foo[A](z: A) + implicit def foo1[A](a: A): Foo[A] = new Foo(a) + implicit def foo2(a: Any): Foo[String] = new Foo("123") + + val a: Foo[_] = "abc" + +} \ No newline at end of file diff --git a/test/files/neg/t1878.check b/test/files/neg/t1878.check index f3a6701d41..128741a022 100644 --- a/test/files/neg/t1878.check +++ b/test/files/neg/t1878.check @@ -6,10 +6,13 @@ t1878.scala:3: error: scrutinee is incompatible with pattern type; required: String val err1 = "" match { case Seq(f @ _*, ',') => f } ^ +t1878.scala:3: error: not found: value f + val err1 = "" match { case Seq(f @ _*, ',') => f } + ^ t1878.scala:9: error: _* may only come last val List(List(_*, arg2), _) = List(List(1,2,3), List(4,5,6)) ^ t1878.scala:13: error: _* may only come last case

{ _* }

=> ^ -four errors found +5 errors found diff --git a/test/files/neg/t2641.check b/test/files/neg/t2641.check index 2056a1b9ab..9e2f02ac47 100644 --- a/test/files/neg/t2641.check +++ b/test/files/neg/t2641.check @@ -1,4 +1,4 @@ -t2641.scala:18: error: illegal cyclic reference involving trait ManagedSeq +t2641.scala:18: error: wrong number of type arguments for ManagedSeq, should be 2 with TraversableViewLike[A, ManagedSeqStrict[A], ManagedSeq[A]] ^ t2641.scala:16: error: illegal inheritance; @@ -13,23 +13,7 @@ t2641.scala:16: error: illegal inheritance; self-type ManagedSeq does not conform to ScalaObject's selftype ScalaObject extends ManagedSeqStrict[A] ^ -t2641.scala:24: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = typer - trait Transformed[+B] extends ManagedSeq[B, Coll] with super.Transformed[B] - ^ -t2641.scala:26: error: something is wrong (wrong class file?): trait ManagedSeq with type parameters [A,Coll] gets applied to arguments [], phase = namer - trait Sliced extends Transformed[A] with super.Sliced { - ^ -t2641.scala:26: error: illegal inheritance; superclass Any - is not a subclass of the superclass ManagedSeqStrict - of the mixin trait Transformed - trait Sliced extends Transformed[A] with super.Sliced { - ^ -t2641.scala:26: error: illegal inheritance; superclass Any - is not a subclass of the superclass Object - of the mixin trait Sliced - trait Sliced extends Transformed[A] with super.Sliced { - ^ t2641.scala:27: error: value managedIterator is not a member of ManagedSeq override def managedIterator = self.managedIterator slice (from, until) ^ -9 errors found +5 errors found diff --git a/test/files/neg/t2918.check b/test/files/neg/t2918.check index 263beab518..aae3045e8a 100644 --- a/test/files/neg/t2918.check +++ b/test/files/neg/t2918.check @@ -1,10 +1,10 @@ t2918.scala:2: error: illegal cyclic reference involving type A - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ t2918.scala:2: error: cyclic aliasing or subtyping involving type A - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ t2918.scala:2: error: A does not take type parameters - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x ^ three errors found diff --git a/test/files/neg/t2918.scala b/test/files/neg/t2918.scala index 03477ccfbf..ff2be39ae0 100755 --- a/test/files/neg/t2918.scala +++ b/test/files/neg/t2918.scala @@ -1,3 +1,3 @@ object Test { - def g[X, A[X] <: A[X]](x: A[X]) = x + def g[X, A[X] <: A[X]](x: A[X]) = x } diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check index 0b394e23d6..53221b7ca0 100644 --- a/test/files/neg/t3015.check +++ b/test/files/neg/t3015.check @@ -3,9 +3,4 @@ t3015.scala:7: error: scrutinee is incompatible with pattern type; required: String val b(foo) = "foo" ^ -t3015.scala:7: error: type mismatch; - found : String with _$1(in object Test) where type +_$1(in object Test) - required: (some other)_$1(in object Test) where type +(some other)_$1(in object Test) - val b(foo) = "foo" - ^ -two errors found +one error found diff --git a/test/files/neg/t649.check b/test/files/neg/t649.check index 5a270d4751..a6670886b5 100644 --- a/test/files/neg/t649.check +++ b/test/files/neg/t649.check @@ -1,4 +1,4 @@ t649.scala:3: error: overloaded method foo needs result type def foo[A] = foo[A] - ^ + ^ one error found -- cgit v1.2.3 From 9b9fb2cad46041c6cf101ec436b643e3e922bd35 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 26 Jan 2012 13:19:41 -0800 Subject: Disabled "not found" suggestions. The benchmarks charts are confusing me and I want to rule it out as a problem by not having it exist for a while. --- src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 4 ++++ test/files/neg/nopredefs.check | 2 +- test/files/neg/suggest-similar.check | 6 +++--- test/files/neg/t2870.check | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 8af8bbc6ca..6ee09d064f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -171,6 +171,8 @@ trait ContextErrors { NormalTypeError(tree, "reference to " + name + " is ambiguous;\n" + msg) def SymbolNotFoundError(tree: Tree, name: Name, owner: Symbol, startingIdentCx: Context) = { + /*** Disabled pending investigation of performance impact. + // This laborious determination arrived at to keep the tests working. val calcSimilar = ( name.length > 2 && ( @@ -196,6 +198,8 @@ trait ContextErrors { similarString("" + name, allowedStrings) } } + */ + val similar = "" NormalTypeError(tree, "not found: "+decodeWithKind(name, owner) + similar) } diff --git a/test/files/neg/nopredefs.check b/test/files/neg/nopredefs.check index e6c1af78a0..0a0ab34482 100644 --- a/test/files/neg/nopredefs.check +++ b/test/files/neg/nopredefs.check @@ -1,4 +1,4 @@ -nopredefs.scala:5: error: not found: value Set (similar: Seq) +nopredefs.scala:5: error: not found: value Set val y = Set(3) ^ one error found diff --git a/test/files/neg/suggest-similar.check b/test/files/neg/suggest-similar.check index 0a858aaf2e..057aa8b250 100644 --- a/test/files/neg/suggest-similar.check +++ b/test/files/neg/suggest-similar.check @@ -1,10 +1,10 @@ -suggest-similar.scala:8: error: not found: value flippitx (similar: flippity) +suggest-similar.scala:8: error: not found: value flippitx flippitx = 123 ^ -suggest-similar.scala:9: error: not found: value identiyt (similar: identity) +suggest-similar.scala:9: error: not found: value identiyt Nil map identiyt ^ -suggest-similar.scala:10: error: not found: type Bingus (similar: Dingus) +suggest-similar.scala:10: error: not found: type Bingus new Bingus ^ three errors found diff --git a/test/files/neg/t2870.check b/test/files/neg/t2870.check index ab962d48c8..99522eca65 100644 --- a/test/files/neg/t2870.check +++ b/test/files/neg/t2870.check @@ -1,4 +1,4 @@ -t2870.scala:1: error: not found: type Jar (similar: Jars) +t2870.scala:1: error: not found: type Jar class Jars(jar: Jar) ^ t2870.scala:4: error: encountered unrecoverable cycle resolving import. -- cgit v1.2.3 From 0d0cdea28ec142a3e6da7a29b8130138a41ae782 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 27 Jan 2012 20:09:38 -0800 Subject: Test case closes SI-3854. --- test/files/neg/t3854.check | 5 +++++ test/files/neg/t3854.scala | 15 +++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/files/neg/t3854.check create mode 100644 test/files/neg/t3854.scala (limited to 'test/files/neg') diff --git a/test/files/neg/t3854.check b/test/files/neg/t3854.check new file mode 100644 index 0000000000..c478481a6f --- /dev/null +++ b/test/files/neg/t3854.check @@ -0,0 +1,5 @@ +t3854.scala:1: error: class Bar needs to be abstract, since method foo in trait Foo of type [G[_]](implicit n: N[G,F])X[F] is not defined +(Note that N[G,F] does not match M[G]) +class Bar[F[_]] extends Foo[F] { + ^ +one error found diff --git a/test/files/neg/t3854.scala b/test/files/neg/t3854.scala new file mode 100644 index 0000000000..e8db76c0a5 --- /dev/null +++ b/test/files/neg/t3854.scala @@ -0,0 +1,15 @@ +class Bar[F[_]] extends Foo[F] { + def foo[G[_[_], _]](implicit M: M[G]): X[({type λ[α] = G[F, α] })#λ] = null +} +// vim: set ts=4 sw=4 et: + +trait M[F[_[_], _]] +trait N[F[_], G[_]] + +trait X[F[_]] { + def apply[A]: F[A] +} + +trait Foo[F[_]] { + def foo[G[_]](implicit n: N[G, F]): X[F] +} -- cgit v1.2.3 From 818afc61dd508d601369e7a881eb0d2b97e07b77 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 29 Jan 2012 13:47:17 -0800 Subject: Test case closes SI-4515. --- test/files/neg/t4515.check | 6 ++++++ test/files/neg/t4515.scala | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/files/neg/t4515.check create mode 100644 test/files/neg/t4515.scala (limited to 'test/files/neg') diff --git a/test/files/neg/t4515.check b/test/files/neg/t4515.check new file mode 100644 index 0000000000..ce5350b35f --- /dev/null +++ b/test/files/neg/t4515.check @@ -0,0 +1,6 @@ +t4515.scala:37: error: type mismatch; + found : _0(in value $anonfun) where type _0(in value $anonfun) + required: (some other)_0(in value $anonfun) where type +(some other)_0(in value $anonfun) + handler.onEvent(target, ctx.getEvent, node, ctx) + ^ +one error found diff --git a/test/files/neg/t4515.scala b/test/files/neg/t4515.scala new file mode 100644 index 0000000000..63049f201d --- /dev/null +++ b/test/files/neg/t4515.scala @@ -0,0 +1,41 @@ +import scala.collection.mutable.HashMap + +object Main { + trait Target { } + + trait PushEventContext[EventType] { + def getEvent: EventType + } + trait PushNode[EventType] { } + trait DerivedPushNode[EventType] extends PushNode[EventType] { } + + trait HandlerBase[EventType] { + def onEvent(target: Target, + event: EventType, + node: PushNode[EventType], + ctx: PushEventContext[EventType]): Unit + } + val handlers = new HashMap[DerivedPushNode[_], HandlerBase[_]] + + object TimerPushService { + private val INSTANCE: TimerPushService = new TimerPushService + def get: TimerPushService = INSTANCE + } + + class TimerPushService { + def add[EventType](node: DerivedPushNode[EventType], + context: PushEventContext[EventType]): Unit = {} + + def pollEvents[EventType](node: DerivedPushNode[EventType]): List[PushEventContext[EventType]] = + Nil + } + + def onTimer(target: Target) { + val pushService = TimerPushService.get + for ((node, handler) <- handlers) { + for (ctx <- pushService.pollEvents(node)) { + handler.onEvent(target, ctx.getEvent, node, ctx) + } + } + } +} \ No newline at end of file -- cgit v1.2.3 From 147e9eaf3814738f339b020e701a160ba2f68b60 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 31 Jan 2012 08:21:34 -0800 Subject: Improved warning for insensible comparisons. Utilize knowledge of case class synthetic equals to rule out some comparisons statically. Closes SI-5426. --- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 11 +++++++---- test/files/neg/checksensible.check | 5 ++++- test/files/neg/t5426.check | 13 +++++++++++++ test/files/neg/t5426.flags | 1 + test/files/neg/t5426.scala | 10 ++++++++++ 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/files/neg/t5426.check create mode 100644 test/files/neg/t5426.flags create mode 100644 test/files/neg/t5426.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index a99d09173e..a6c2f75d5e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1034,10 +1034,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R /** Symbols which limit the warnings we can issue since they may be value types */ val isMaybeValue = Set(AnyClass, AnyRefClass, AnyValClass, ObjectClass, ComparableClass, JavaSerializableClass) - // Whether def equals(other: Any) is overridden - def isUsingDefaultEquals = { + // Whether def equals(other: Any) is overridden or synthetic + def isUsingWarnableEquals = { val m = receiver.info.member(nme.equals_) - (m == Object_equals) || (m == Any_equals) + (m == Object_equals) || (m == Any_equals) || (m.isSynthetic && m.owner.isCase) } // Whether this == or != is one of those defined in Any/AnyRef or an overload from elsewhere. def isUsingDefaultScalaOp = { @@ -1045,7 +1045,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R (s == Object_==) || (s == Object_!=) || (s == Any_==) || (s == Any_!=) } // Whether the operands+operator represent a warnable combo (assuming anyrefs) - def isWarnable = isReferenceOp || (isUsingDefaultEquals && isUsingDefaultScalaOp) + // Looking for comparisons performed with ==/!= in combination with either an + // equals method inherited from Object or a case class synthetic equals (for + // which we know the logic.) + def isWarnable = isReferenceOp || (isUsingDefaultScalaOp && isUsingWarnableEquals) def isEitherNullable = (NullClass.tpe <:< receiver.info) || (NullClass.tpe <:< actual.info) def isBoolean(s: Symbol) = unboxedValueClass(s) == BooleanClass def isUnit(s: Symbol) = unboxedValueClass(s) == UnitClass diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index 0881205bb4..d785179a56 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -28,6 +28,9 @@ checksensible.scala:27: error: comparing values of types Int and Unit using `==' checksensible.scala:29: error: comparing values of types Int and String using `==' will always yield false 1 == "abc" ^ +checksensible.scala:33: error: comparing values of types Some[Int] and Int using `==' will always yield false + Some(1) == 1 // as above + ^ checksensible.scala:38: error: comparing a fresh object using `==' will always yield false new AnyRef == 1 ^ @@ -94,4 +97,4 @@ checksensible.scala:84: error: comparing values of types EqEqRefTest.this.C3 and checksensible.scala:95: error: comparing values of types Unit and Int using `!=' will always yield true while ((c = in.read) != -1) ^ -32 errors found +33 errors found diff --git a/test/files/neg/t5426.check b/test/files/neg/t5426.check new file mode 100644 index 0000000000..d9e192d3f0 --- /dev/null +++ b/test/files/neg/t5426.check @@ -0,0 +1,13 @@ +t5426.scala:2: error: comparing values of types Some[Int] and Int using `==' will always yield false + def f1 = Some(5) == 5 + ^ +t5426.scala:3: error: comparing values of types Int and Some[Int] using `==' will always yield false + def f2 = 5 == Some(5) + ^ +t5426.scala:8: error: comparing values of types Int and Some[Int] using `==' will always yield false + (x1 == x2) + ^ +t5426.scala:9: error: comparing values of types Some[Int] and Int using `==' will always yield false + (x2 == x1) + ^ +four errors found diff --git a/test/files/neg/t5426.flags b/test/files/neg/t5426.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t5426.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t5426.scala b/test/files/neg/t5426.scala new file mode 100644 index 0000000000..f2fb5cc12c --- /dev/null +++ b/test/files/neg/t5426.scala @@ -0,0 +1,10 @@ +class A { + def f1 = Some(5) == 5 + def f2 = 5 == Some(5) + + val x1 = 5 + val x2 = Some(5) + + (x1 == x2) + (x2 == x1) +} -- cgit v1.2.3 From 37bcff7956451cd74d08899e0e49c8b569d3a882 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 31 Jan 2012 09:03:32 -0800 Subject: Test case closes SI-5352. --- test/files/neg/t5352.check | 13 +++++++++++++ test/files/neg/t5352.flags | 1 + test/files/neg/t5352.scala | 15 +++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 test/files/neg/t5352.check create mode 100644 test/files/neg/t5352.flags create mode 100644 test/files/neg/t5352.scala (limited to 'test/files/neg') diff --git a/test/files/neg/t5352.check b/test/files/neg/t5352.check new file mode 100644 index 0000000000..d24b0e8ee1 --- /dev/null +++ b/test/files/neg/t5352.check @@ -0,0 +1,13 @@ +t5352.scala:11: error: type mismatch; + found : boop.Bar + required: boop.BarF + (which expands to) AnyRef{def f(): Int} + x = xs.head + ^ +t5352.scala:14: error: method f in class Bar1 cannot be accessed in boop.Bar1 + Access to protected method f not permitted because + enclosing object boop is not a subclass of + class Bar1 in object boop where target is defined + (new Bar1).f + ^ +two errors found diff --git a/test/files/neg/t5352.flags b/test/files/neg/t5352.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/t5352.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/t5352.scala b/test/files/neg/t5352.scala new file mode 100644 index 0000000000..6ee41f5680 --- /dev/null +++ b/test/files/neg/t5352.scala @@ -0,0 +1,15 @@ +object boop { + abstract class Bar { protected def f(): Any } + class Bar1 extends Bar { protected def f(): Int = 5 } + class Bar2 extends Bar { protected def f(): Int = 5 } + + val xs = List(new Bar1, new Bar2) + + type BarF = { def f(): Int } + + var x: BarF = _ + x = xs.head + x.f + + (new Bar1).f +} -- cgit v1.2.3 From f55db64983edfeb9484b7617e2b59f8994c37ef3 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 1 Feb 2012 08:06:24 -0800 Subject: Fix for bad bug with accidental overrides. An object in a subclass would silently override an inherited method, then throw a CCE at runtime. I blamed this on matchesType and altered it accordingly. There's a pretty extensive test case which reflects my expectations. Review by @odersky please. Closes SI-5429. --- src/compiler/scala/reflect/internal/Types.scala | 10 ++ .../tools/nsc/transform/OverridingPairs.scala | 10 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 2 + test/files/neg/t5429.check | 132 +++++++++++++++++++++ test/files/neg/t5429.scala | 93 +++++++++++++++ 5 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 test/files/neg/t5429.check create mode 100644 test/files/neg/t5429.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 371fb8d585..c8b960ebe8 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -5477,6 +5477,8 @@ trait Types extends api.Types { self: SymbolTable => else matchesType(tp1, res2, alwaysMatchSimple) case ExistentialType(_, res2) => alwaysMatchSimple && matchesType(tp1, res2, true) + case TypeRef(_, sym, Nil) => + params1.isEmpty && sym.isModuleClass && matchesType(res1, sym.tpe, alwaysMatchSimple) case _ => false } @@ -5488,6 +5490,8 @@ trait Types extends api.Types { self: SymbolTable => matchesType(res1, res2, alwaysMatchSimple) case ExistentialType(_, res2) => alwaysMatchSimple && matchesType(tp1, res2, true) + case TypeRef(_, sym, Nil) if sym.isModuleClass => + matchesType(res1, sym.tpe, alwaysMatchSimple) case _ => matchesType(res1, tp2, alwaysMatchSimple) } @@ -5508,6 +5512,12 @@ trait Types extends api.Types { self: SymbolTable => if (alwaysMatchSimple) matchesType(res1, tp2, true) else lastTry } + case TypeRef(_, sym, Nil) if sym.isModuleClass => + tp2 match { + case MethodType(Nil, res2) => matchesType(sym.tpe, res2, alwaysMatchSimple) + case NullaryMethodType(res2) => matchesType(sym.tpe, res2, alwaysMatchSimple) + case _ => lastTry + } case _ => lastTry } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 1200e973c5..e49f8d7c0b 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -45,8 +45,14 @@ abstract class OverridingPairs { * Types always match. Term symbols match if their membertypes * relative to .this do */ - protected def matches(sym1: Symbol, sym2: Symbol): Boolean = - sym1.isType || (self.memberType(sym1) matches self.memberType(sym2)) + protected def matches(sym1: Symbol, sym2: Symbol): Boolean = { + def tp_s(s: Symbol) = self.memberType(s) + "/" + self.memberType(s).getClass + val result = sym1.isType || (self.memberType(sym1) matches self.memberType(sym2)) + debuglog("overriding-pairs? %s matches %s (%s vs. %s) == %s".format( + sym1.fullLocationString, sym2.fullLocationString, tp_s(sym1), tp_s(sym2), result)) + + result + } /** An implementation of BitSets as arrays (maybe consider collection.BitSet * for that?) The main purpose of this is to implement diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index a6c2f75d5e..5aa1843188 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -276,6 +276,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R * of class `clazz` are met. */ def checkOverride(member: Symbol, other: Symbol) { + debuglog("Checking validity of %s overriding %s".format(member.fullLocationString, other.fullLocationString)) + def memberTp = self.memberType(member) def otherTp = self.memberType(other) def noErrorType = other.tpe != ErrorType && member.tpe != ErrorType diff --git a/test/files/neg/t5429.check b/test/files/neg/t5429.check new file mode 100644 index 0000000000..1b89c59587 --- /dev/null +++ b/test/files/neg/t5429.check @@ -0,0 +1,132 @@ +t5429.scala:20: error: overriding value value in class A of type Int; + object value needs `override' modifier + object value // fail + ^ +t5429.scala:21: error: overriding lazy value lazyvalue in class A of type Int; + object lazyvalue needs `override' modifier + object lazyvalue // fail + ^ +t5429.scala:22: error: overriding method nullary in class A of type => Int; + object nullary needs `override' modifier + object nullary // fail + ^ +t5429.scala:23: error: overriding method emptyArg in class A of type ()Int; + object emptyArg needs `override' modifier + object emptyArg // fail + ^ +t5429.scala:27: error: overriding value value in class A0 of type Any; + object value needs `override' modifier + object value // fail + ^ +t5429.scala:28: error: overriding lazy value lazyvalue in class A0 of type Any; + object lazyvalue needs `override' modifier + object lazyvalue // fail + ^ +t5429.scala:29: error: overriding method nullary in class A0 of type => Any; + object nullary needs `override' modifier + object nullary // fail + ^ +t5429.scala:30: error: overriding method emptyArg in class A0 of type ()Any; + object emptyArg needs `override' modifier + object emptyArg // fail + ^ +t5429.scala:35: error: overriding value value in class A of type Int; + object value has incompatible type + override object value // fail + ^ +t5429.scala:36: error: overriding lazy value lazyvalue in class A of type Int; + object lazyvalue must be declared lazy to override a concrete lazy value + override object lazyvalue // fail + ^ +t5429.scala:37: error: overriding method nullary in class A of type => Int; + object nullary has incompatible type + override object nullary // fail + ^ +t5429.scala:38: error: overriding method emptyArg in class A of type ()Int; + object emptyArg has incompatible type + override object emptyArg // fail + ^ +t5429.scala:39: error: object oneArg overrides nothing + override object oneArg // fail + ^ +t5429.scala:43: error: overriding lazy value lazyvalue in class A0 of type Any; + object lazyvalue must be declared lazy to override a concrete lazy value + override object lazyvalue // !!! this fails, but should succeed (lazy over lazy) + ^ +t5429.scala:46: error: object oneArg overrides nothing + override object oneArg // fail + ^ +t5429.scala:50: error: overriding value value in class A of type Int; + value value needs `override' modifier + val value = 0 // fail + ^ +t5429.scala:51: error: overriding lazy value lazyvalue in class A of type Int; + value lazyvalue needs `override' modifier + val lazyvalue = 0 // fail + ^ +t5429.scala:52: error: overriding method nullary in class A of type => Int; + value nullary needs `override' modifier + val nullary = 5 // fail + ^ +t5429.scala:53: error: overriding method emptyArg in class A of type ()Int; + value emptyArg needs `override' modifier + val emptyArg = 10 // fail + ^ +t5429.scala:58: error: overriding lazy value lazyvalue in class A0 of type Any; + value lazyvalue must be declared lazy to override a concrete lazy value + override val lazyvalue = 0 // fail (non-lazy) + ^ +t5429.scala:61: error: value oneArg overrides nothing + override val oneArg = 15 // fail + ^ +t5429.scala:65: error: overriding value value in class A of type Int; + method value needs `override' modifier + def value = 0 // fail + ^ +t5429.scala:66: error: overriding lazy value lazyvalue in class A of type Int; + method lazyvalue needs `override' modifier + def lazyvalue = 2 // fail + ^ +t5429.scala:67: error: overriding method nullary in class A of type => Int; + method nullary needs `override' modifier + def nullary = 5 // fail + ^ +t5429.scala:68: error: overriding method emptyArg in class A of type ()Int; + method emptyArg needs `override' modifier + def emptyArg = 10 // fail + ^ +t5429.scala:72: error: overriding value value in class A0 of type Any; + method value needs to be a stable, immutable value + override def value = 0 // fail + ^ +t5429.scala:73: error: overriding lazy value lazyvalue in class A0 of type Any; + method lazyvalue needs to be a stable, immutable value + override def lazyvalue = 2 // fail + ^ +t5429.scala:76: error: method oneArg overrides nothing + override def oneArg = 15 // fail + ^ +t5429.scala:80: error: overriding value value in class A of type Int; + lazy value value needs `override' modifier + lazy val value = 0 // fail + ^ +t5429.scala:81: error: overriding lazy value lazyvalue in class A of type Int; + lazy value lazyvalue needs `override' modifier + lazy val lazyvalue = 2 // fail + ^ +t5429.scala:82: error: overriding method nullary in class A of type => Int; + lazy value nullary needs `override' modifier + lazy val nullary = 5 // fail + ^ +t5429.scala:83: error: overriding method emptyArg in class A of type ()Int; + lazy value emptyArg needs `override' modifier + lazy val emptyArg = 10 // fail + ^ +t5429.scala:87: error: overriding value value in class A0 of type Any; + lazy value value cannot override a concrete non-lazy value + override lazy val value = 0 // fail (strict over lazy) + ^ +t5429.scala:91: error: value oneArg overrides nothing + override lazy val oneArg = 15 // fail + ^ +34 errors found diff --git a/test/files/neg/t5429.scala b/test/files/neg/t5429.scala new file mode 100644 index 0000000000..1cd4dcd032 --- /dev/null +++ b/test/files/neg/t5429.scala @@ -0,0 +1,93 @@ +// /scala/trac/5429/a.scala +// Wed Feb 1 08:05:27 PST 2012 + +class A { + val value = 0 + lazy val lazyvalue = 2 + def nullary = 5 + def emptyArg() = 10 + def oneArg(x: String) = 15 +} +class A0 { + val value: Any = 0 + lazy val lazyvalue: Any = 2 + def nullary: Any = 5 + def emptyArg(): Any = 10 + def oneArg(x: String): Any = 15 +} + +class B extends A { + object value // fail + object lazyvalue // fail + object nullary // fail + object emptyArg // fail + object oneArg // overload +} +class B0 extends A0 { + object value // fail + object lazyvalue // fail + object nullary // fail + object emptyArg // fail + object oneArg // overload +} + +class C extends A { + override object value // fail + override object lazyvalue // fail + override object nullary // fail + override object emptyArg // fail + override object oneArg // fail +} +class C0 extends A0 { + override object value // !!! this succeeds, but should fail (lazy over strict) + override object lazyvalue // !!! this fails, but should succeed (lazy over lazy) + override object nullary // override + override object emptyArg // override + override object oneArg // fail +} + +class D extends A { + val value = 0 // fail + val lazyvalue = 0 // fail + val nullary = 5 // fail + val emptyArg = 10 // fail + val oneArg = 15 // overload +} +class D0 extends A0 { + override val value = 0 // override + override val lazyvalue = 0 // fail (non-lazy) + override val nullary = 5 // override + override val emptyArg = 10 // override + override val oneArg = 15 // fail +} + +class E extends A { + def value = 0 // fail + def lazyvalue = 2 // fail + def nullary = 5 // fail + def emptyArg = 10 // fail + def oneArg = 15 // overload +} +class E0 extends A0 { + override def value = 0 // fail + override def lazyvalue = 2 // fail + override def nullary = 5 // override + override def emptyArg = 10 // override + override def oneArg = 15 // fail +} + +class F extends A { + lazy val value = 0 // fail + lazy val lazyvalue = 2 // fail + lazy val nullary = 5 // fail + lazy val emptyArg = 10 // fail + lazy val oneArg = 15 // overload +} +class F0 extends A0 { + override lazy val value = 0 // fail (strict over lazy) + override lazy val lazyvalue = 2 // override (lazy over lazy) + override lazy val nullary = 5 // override + override lazy val emptyArg = 10 // override + override lazy val oneArg = 15 // fail +} + -- cgit v1.2.3 From 264ff5d5e8dbec4ae2e13bf52e66a965d884b25c Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 31 Jan 2012 00:14:47 -0800 Subject: Fix for parser OOM. The scanner performs some sketchy heuristics when it sees an ascii 1A since it may be EOF or it may be part of a literal. Due to this, it failed to detect an unterminated string literal if the opening quote was unicode-escaped, leading to memory exhaustion as it read SUs until the universe ended. We're parsing a fixed input with known length! There's no reason to be guessing about whether a char is EOF. If we're at the end of the file, it's the end of file. Otherwise, it is not the end of the file. --- src/compiler/scala/tools/nsc/ast/parser/Scanners.scala | 10 ++++++---- test/files/neg/unicode-unterminated-quote.check | 4 ++++ test/files/neg/unicode-unterminated-quote.scala | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 test/files/neg/unicode-unterminated-quote.check create mode 100644 test/files/neg/unicode-unterminated-quote.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 4478fb6128..dae264fffe 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -84,6 +84,8 @@ trait Scanners extends ScannersCommon { abstract class Scanner extends CharArrayReader with TokenData with ScannerCommon { private def isDigit(c: Char) = java.lang.Character isDigit c + + def isAtEnd = charOffset >= buf.length def flush = { charOffset = offset; nextChar(); this } @@ -449,7 +451,7 @@ trait Scanners extends ScannersCommon { case ']' => nextChar(); token = RBRACKET case SU => - if (charOffset >= buf.length) token = EOF + if (isAtEnd) token = EOF else { syntaxError("illegal character") nextChar() @@ -771,10 +773,10 @@ trait Scanners extends ScannersCommon { putChar(ch) } - private def getLitChars(delimiter: Char) = - while (ch != delimiter && (ch != CR && ch != LF && ch != SU || isUnicodeEscape)) { + private def getLitChars(delimiter: Char) = { + while (ch != delimiter && !isAtEnd && (ch != SU && ch != CR && ch != LF || isUnicodeEscape)) getLitChar() - } + } /** read fractional part and exponent of floating point number * if one is present. diff --git a/test/files/neg/unicode-unterminated-quote.check b/test/files/neg/unicode-unterminated-quote.check new file mode 100644 index 0000000000..fc5caa6d7e --- /dev/null +++ b/test/files/neg/unicode-unterminated-quote.check @@ -0,0 +1,4 @@ +unicode-unterminated-quote.scala:2: error: unclosed string literal + val x = /u0022 + ^ +one error found diff --git a/test/files/neg/unicode-unterminated-quote.scala b/test/files/neg/unicode-unterminated-quote.scala new file mode 100644 index 0000000000..bb6eab667f --- /dev/null +++ b/test/files/neg/unicode-unterminated-quote.scala @@ -0,0 +1,2 @@ +class A { + val x = \u0022 \ No newline at end of file -- cgit v1.2.3 From 7a6fa80937dec6c60efe53c915dfa3ba76b3af87 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 11 Feb 2012 13:16:06 -0800 Subject: Another existential problem down. There is a window of danger when multiple related elements are being typed where something which is conceptually one thing can slip into two things, and those two things can be incompatible with one another. Less mysteriously, c478eb770d fixed this: def f = { object Bob ; Bob } ; val g = f But, it did not fix this: def f = { case class Bob() ; Bob } ; val g = f See test case pos/existentials-harmful.scala for an "in the wild" code example fixed by this commit. The root of the problem was that the getter and the field would each independently derive the same existential type to describe Bob, but those existentials were not the same as one another. This has been the most elusive bug I have ever fixed. I want to cry when I think of how much time I've put into it over the past half decade or so. Unfortunately the way the repl works it is particularly good at eliciting those grotesque found/required error messages and so I was never able to let the thing go. There is still a cosmetic issue (from the last commit really) where compound types wind up with repeated parents. Closes SI-1195, SI-1201. --- .../tools/nsc/typechecker/MethodSynthesis.scala | 43 ++++++++----- test/files/neg/t935.check | 5 +- test/files/pos/existentials-harmful.scala | 54 ++++++++++++++++ test/files/pos/existentials.scala | 9 +++ test/files/run/existentials3.check | 22 +++++++ test/files/run/existentials3.scala | 73 ++++++++++++++++++++++ test/files/run/repl-existentials.check | 63 ------------------- test/files/run/repl-existentials.scala | 31 --------- test/files/run/t1195.check | 6 ++ test/files/run/t1195.scala | 26 ++++++++ test/pending/pos/existentials-harmful.scala | 54 ---------------- 11 files changed, 222 insertions(+), 164 deletions(-) create mode 100644 test/files/pos/existentials-harmful.scala create mode 100644 test/files/pos/existentials.scala create mode 100644 test/files/run/existentials3.check create mode 100644 test/files/run/existentials3.scala delete mode 100644 test/files/run/repl-existentials.check delete mode 100644 test/files/run/repl-existentials.scala create mode 100644 test/files/run/t1195.check create mode 100644 test/files/run/t1195.scala delete mode 100644 test/pending/pos/existentials-harmful.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 0c32ff32c0..915d7a98db 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -326,22 +326,35 @@ trait MethodSynthesis { super.validate() } - // keep type tree of original abstract field - private def fixTypeTree(dd: DefDef): DefDef = { - dd.tpt match { - case tt: TypeTree if dd.rhs == EmptyTree => - tt setOriginal tree.tpt - case tpt => - tpt setPos tree.tpt.pos.focus - } - dd - } override def derivedTree: DefDef = { - fixTypeTree { - DefDef(derivedSym, - if (mods.isDeferred) EmptyTree - else gen.mkCheckInit(fieldSelection) - ) + // For existentials, don't specify a type for the getter, even one derived + // from the symbol! This leads to incompatible existentials for the field and + // the getter. Let the typer do all the work. You might think "why only for + // existentials, why not always," and you would be right, except: a single test + // fails, but it looked like some work to deal with it. Test neg/t0606.scala + // starts compiling (instead of failing like it's supposed to) because the typer + // expects to be able to identify escaping locals in typedDefDef, and fails to + // spot that brand of them. In other words it's an artifact of the implementation. + val tpt = derivedSym.tpe.finalResultType match { + case ExistentialType(_, _) => TypeTree() + case tp => TypeTree(tp) + } + tpt setPos focusPos(derivedSym.pos) + // keep type tree of original abstract field + if (mods.isDeferred) + tpt setOriginal tree.tpt + + // TODO - reconcile this with the DefDef creator in Trees (which + // at this writing presented no way to pass a tree in for tpt.) + atPos(derivedSym.pos) { + DefDef( + Modifiers(derivedSym.flags), + derivedSym.name.toTermName, + Nil, + Nil, + tpt, + if (mods.isDeferred) EmptyTree else gen.mkCheckInit(fieldSelection) + ) setSymbol derivedSym } } } diff --git a/test/files/neg/t935.check b/test/files/neg/t935.check index af634a2630..8b73700187 100644 --- a/test/files/neg/t935.check +++ b/test/files/neg/t935.check @@ -4,4 +4,7 @@ t935.scala:7: error: type arguments [Test3.B] do not conform to class E's type p t935.scala:13: error: type arguments [Test4.B] do not conform to class E's type parameter bounds [T <: String] val b: String @E[B](new B) = "hi" ^ -two errors found +t935.scala:13: error: type arguments [Test4.B] do not conform to class E's type parameter bounds [T <: String] + val b: String @E[B](new B) = "hi" + ^ +three errors found diff --git a/test/files/pos/existentials-harmful.scala b/test/files/pos/existentials-harmful.scala new file mode 100644 index 0000000000..8722852e8a --- /dev/null +++ b/test/files/pos/existentials-harmful.scala @@ -0,0 +1,54 @@ +// a.scala +// Mon Jul 11 14:18:26 PDT 2011 + +object ExistentialsConsideredHarmful { + class Animal(val name: String) + object Dog extends Animal("Dog") + object Sheep extends Animal("Sheep") + + trait Tools[A] { + def shave(a: A): A + } + def tools[A](a: A): Tools[A] = null // dummy + + case class TransportBox[A <: Animal](animal: A, tools: Tools[A]) { + def label: String = animal.name + } + + // 1. + def carry[A <: Animal](box: TransportBox[A]): Unit = { + println(box.animal.name+" got carried away") + } + + val aBox = + if (math.random < 0.5) + TransportBox(Dog, tools(Dog)) + else + TransportBox(Sheep, tools(Sheep)) + + // 2. + //aBox.tools.shave(aBox.animal) + + // Use pattern match to avoid opening the existential twice + aBox match { + case TransportBox(animal, tools) => tools.shave(animal) + } + + abstract class BoxCarrier[R <: Animal](box: TransportBox[R]) { + def speed: Int + + def talkToAnimal: Unit = println("The carrier says hello to"+box.animal.name) + } + + // 3. + //val bc = new BoxCarrier(aBox) { + + // Use pattern match to avoid opening the existential twice + // Type annotation on bc is required ... possible compiler bug? + // val bc : BoxCarrier[_ <: Animal] = aBox match { + val bc = aBox match { + case tb : TransportBox[a] => new BoxCarrier(tb) { + def speed: Int = 12 + } + } +} diff --git a/test/files/pos/existentials.scala b/test/files/pos/existentials.scala new file mode 100644 index 0000000000..c51f60b546 --- /dev/null +++ b/test/files/pos/existentials.scala @@ -0,0 +1,9 @@ +class A { + def f() = { case class Bob(); Bob } + + val quux0 = f() + def quux1 = f() + + val bippy0 = f _ + def bippy1 = f _ +} diff --git a/test/files/run/existentials3.check b/test/files/run/existentials3.check new file mode 100644 index 0000000000..41dc1f767c --- /dev/null +++ b/test/files/run/existentials3.check @@ -0,0 +1,22 @@ +_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object +_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable +Object with Test$ToS with scala.ScalaObject +Object with Test$ToS with scala.ScalaObject +Object with Test$ToS with scala.ScalaObject +scala.Function0[Object with Test$ToS with scala.ScalaObject] +scala.Function0[Object with Test$ToS with scala.ScalaObject] +_ <: Object with _ <: Object with Object with Test$ToS with scala.ScalaObject +_ <: Object with _ <: Object with _ <: Object with Test$ToS with scala.ScalaObject +scala.collection.immutable.List[Object with scala.collection.Seq[Int] with scala.ScalaObject] +scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with scala.ScalaObject] +_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object +_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable +Object with Test$ToS with scala.ScalaObject +Object with Test$ToS with scala.ScalaObject +Object with Test$ToS with scala.ScalaObject +scala.Function0[Object with Test$ToS with scala.ScalaObject] +scala.Function0[Object with Test$ToS with scala.ScalaObject] +_ <: Object with _ <: Object with Object with Test$ToS with scala.ScalaObject +_ <: Object with _ <: Object with _ <: Object with Test$ToS with scala.ScalaObject +scala.collection.immutable.List[Object with scala.collection.Seq[Int] with scala.ScalaObject] +scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with scala.ScalaObject] diff --git a/test/files/run/existentials3.scala b/test/files/run/existentials3.scala new file mode 100644 index 0000000000..bb80d366cc --- /dev/null +++ b/test/files/run/existentials3.scala @@ -0,0 +1,73 @@ +object Test { + trait ToS { final override def toString = getClass.getName } + + def f1 = { case class Bar() extends ToS; Bar } + def f2 = { case class Bar() extends ToS; Bar() } + def f3 = { class Bar() extends ToS; object Bar extends ToS; Bar } + def f4 = { class Bar() extends ToS; new Bar() } + def f5 = { object Bar extends ToS; Bar } + def f6 = { () => { object Bar extends ToS ; Bar } } + def f7 = { val f = { () => { object Bar extends ToS ; Bar } } ; f } + + def f8 = { trait A ; trait B extends A ; class C extends B with ToS; new C { } } + def f9 = { trait A ; trait B ; class C extends B with A with ToS; new C { } } + + def f10 = { class A { type T1 } ; List[A#T1]() } + def f11 = { abstract class A extends Seq[Int] ; List[A]() } + def f12 = { abstract class A extends Seq[U forSome { type U <: Int }] ; List[A]() } + + val g1 = { case class Bar() extends ToS; Bar } + val g2 = { case class Bar() extends ToS; Bar() } + val g3 = { class Bar() extends ToS; object Bar extends ToS; Bar } + val g4 = { class Bar() extends ToS; new Bar() } + val g5 = { object Bar extends ToS; Bar } + val g6 = { () => { object Bar extends ToS ; Bar } } + val g7 = { val f = { () => { object Bar extends ToS ; Bar } } ; f } + + val g8 = { trait A ; trait B extends A ; class C extends B with ToS; new C { } } + val g9 = { trait A ; trait B ; class C extends B with A with ToS; new C { } } + + val g10 = { class A { type T1 } ; List[A#T1]() } + val g11 = { abstract class A extends Seq[Int] ; List[A]() } + val g12 = { abstract class A extends Seq[U forSome { type U <: Int }] ; List[A]() } + + def m[T: Manifest](x: T) = println(manifest[T]) + + // manifests don't work for f10/g10 + def main(args: Array[String]): Unit = { + m(f1) + m(f2) + m(f3) + m(f4) + m(f5) + m(f6) + m(f7) + m(f8) + m(f9) + // m(f10) + m(f11) + m(f12) + m(g1) + m(g2) + m(g3) + m(g4) + m(g5) + m(g6) + m(g7) + m(g8) + m(g9) + // m(g10) + m(g11) + m(g12) + } +} + +object Misc { + trait Bippy { def bippy = "I'm Bippy!" } + object o1 { + def f1 = { trait A extends Seq[U forSome { type U <: Bippy }] ; abstract class B extends A ; trait C extends B ; (null: C) } + def f2 = f1.head.bippy + } + def g1 = o1.f1 _ + def g2 = o1.f2 _ +} diff --git a/test/files/run/repl-existentials.check b/test/files/run/repl-existentials.check deleted file mode 100644 index 7093b428e8..0000000000 --- a/test/files/run/repl-existentials.check +++ /dev/null @@ -1,63 +0,0 @@ -Type in expressions to have them evaluated. -Type :help for more information. - -scala> trait ToS { final override def toString = getClass.getName } -defined trait ToS - -scala> - -scala> // def f1 = { case class Bar() extends ToS; Bar } - -scala> def f2 = { case class Bar() extends ToS; Bar() } -f2: Bar forSome { type Bar <: Object with ToS with ScalaObject with Product with Serializable{def copy(): Bar} } - -scala> def f3 = { class Bar() extends ToS; object Bar extends ToS; Bar } -f3: Object with ToS with ScalaObject - -scala> def f4 = { class Bar() extends ToS; new Bar() } -f4: Object with ToS with ScalaObject - -scala> def f5 = { object Bar extends ToS; Bar } -f5: Object with ToS with ScalaObject - -scala> def f6 = { () => { object Bar extends ToS ; Bar } } -f6: () => Object with ToS with ScalaObject - -scala> def f7 = { val f = { () => { object Bar extends ToS ; Bar } } ; f } -f7: () => Object with ToS with ScalaObject - -scala> - -scala> // def f8 = { trait A ; trait B extends A ; class C extends B with ToS; new C { } } - -scala> // def f9 = { trait A ; trait B ; class C extends B with A with ToS; new C { } } - -scala> - -scala> def f10 = { class A { type T1 } ; List[A#T1]() } -f10: List[Object with ScalaObject{type T1}#T1] - -scala> def f11 = { abstract class A extends Seq[Int] ; List[A]() } -f11: List[Object with Seq[Int] with ScalaObject] - -scala> def f12 = { abstract class A extends Seq[U forSome { type U <: Int }] ; List[A]() } -f12: List[Object with Seq[U forSome { type U <: Int }] with ScalaObject] - -scala> - -scala> trait Bippy { def bippy = "I'm Bippy!" } -defined trait Bippy - -scala> object o1 { - def f1 = { trait A extends Seq[U forSome { type U <: Bippy }] ; abstract class B extends A ; trait C extends B ; (null: C) } - def f2 = f1.head.bippy -} -defined module o1 - -scala> o1.f1 _ -res0: () => C forSome { type C <: Object with A with ScalaObject; type A <: Object with Seq[U forSome { type U <: Bippy }] } = - -scala> o1.f2 _ -res1: () => String = - -scala> diff --git a/test/files/run/repl-existentials.scala b/test/files/run/repl-existentials.scala deleted file mode 100644 index 31034b49a0..0000000000 --- a/test/files/run/repl-existentials.scala +++ /dev/null @@ -1,31 +0,0 @@ -import scala.tools.partest.ReplTest - -object Test extends ReplTest { - def code = """ -trait ToS { final override def toString = getClass.getName } - -// def f1 = { case class Bar() extends ToS; Bar } -def f2 = { case class Bar() extends ToS; Bar() } -def f3 = { class Bar() extends ToS; object Bar extends ToS; Bar } -def f4 = { class Bar() extends ToS; new Bar() } -def f5 = { object Bar extends ToS; Bar } -def f6 = { () => { object Bar extends ToS ; Bar } } -def f7 = { val f = { () => { object Bar extends ToS ; Bar } } ; f } - -// def f8 = { trait A ; trait B extends A ; class C extends B with ToS; new C { } } -// def f9 = { trait A ; trait B ; class C extends B with A with ToS; new C { } } - -def f10 = { class A { type T1 } ; List[A#T1]() } -def f11 = { abstract class A extends Seq[Int] ; List[A]() } -def f12 = { abstract class A extends Seq[U forSome { type U <: Int }] ; List[A]() } - -trait Bippy { def bippy = "I'm Bippy!" } -object o1 { - def f1 = { trait A extends Seq[U forSome { type U <: Bippy }] ; abstract class B extends A ; trait C extends B ; (null: C) } - def f2 = f1.head.bippy -} -o1.f1 _ -o1.f2 _ - -""".trim -} diff --git a/test/files/run/t1195.check b/test/files/run/t1195.check new file mode 100644 index 0000000000..dc521fb8ca --- /dev/null +++ b/test/files/run/t1195.check @@ -0,0 +1,6 @@ +_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object +_ <: Object with scala.ScalaObject with scala.Product with scala.Serializable +Object with scala.ScalaObject with scala.Product with scala.Serializable +_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object +_ <: Object with scala.ScalaObject with scala.Product with scala.Serializable +Object with scala.ScalaObject with scala.Product with scala.Serializable diff --git a/test/files/run/t1195.scala b/test/files/run/t1195.scala new file mode 100644 index 0000000000..81ef5bdb0e --- /dev/null +++ b/test/files/run/t1195.scala @@ -0,0 +1,26 @@ +object Test { + def f() = { case class Bar(x: Int); Bar } + def g() = { case class Bar(x: Int); Bar(5) } + def h() = { case object Bar ; Bar } + + val f1 = f() + val g1 = g() + val h1 = h() + + def m[T: Manifest](x: T) = println(manifest[T]) + + def main(args: Array[String]): Unit = { + m(f) + m(g) + m(h) + m(f1) + m(g1) + m(h1) + } +} + +class A1[T] { + class B1[U] { + def f = { case class D(x: Int) extends A1[String] ; new D(5) } + } +} diff --git a/test/pending/pos/existentials-harmful.scala b/test/pending/pos/existentials-harmful.scala deleted file mode 100644 index 8722852e8a..0000000000 --- a/test/pending/pos/existentials-harmful.scala +++ /dev/null @@ -1,54 +0,0 @@ -// a.scala -// Mon Jul 11 14:18:26 PDT 2011 - -object ExistentialsConsideredHarmful { - class Animal(val name: String) - object Dog extends Animal("Dog") - object Sheep extends Animal("Sheep") - - trait Tools[A] { - def shave(a: A): A - } - def tools[A](a: A): Tools[A] = null // dummy - - case class TransportBox[A <: Animal](animal: A, tools: Tools[A]) { - def label: String = animal.name - } - - // 1. - def carry[A <: Animal](box: TransportBox[A]): Unit = { - println(box.animal.name+" got carried away") - } - - val aBox = - if (math.random < 0.5) - TransportBox(Dog, tools(Dog)) - else - TransportBox(Sheep, tools(Sheep)) - - // 2. - //aBox.tools.shave(aBox.animal) - - // Use pattern match to avoid opening the existential twice - aBox match { - case TransportBox(animal, tools) => tools.shave(animal) - } - - abstract class BoxCarrier[R <: Animal](box: TransportBox[R]) { - def speed: Int - - def talkToAnimal: Unit = println("The carrier says hello to"+box.animal.name) - } - - // 3. - //val bc = new BoxCarrier(aBox) { - - // Use pattern match to avoid opening the existential twice - // Type annotation on bc is required ... possible compiler bug? - // val bc : BoxCarrier[_ <: Animal] = aBox match { - val bc = aBox match { - case tb : TransportBox[a] => new BoxCarrier(tb) { - def speed: Int = 12 - } - } -} -- cgit v1.2.3 From 6548dcf12d83e327df2f90048140fb95346b7e95 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 12 Feb 2012 23:07:30 +0100 Subject: reifyAnnotations Annotations are now supported by the reifier: * AnnotationInfos from symbols get transformed back into mods. * AnnotatedTypes are retained and are reified along with AnnotationInfos. Reification is no magic, and reification of annotations especially: * Annotations cannot refer to symbols defined inside the quasiquote. This restriction is due to the fact that we need to erase locally defined symbols before reifying to make subsequent reflective compilations succeed. However, while doing that, we also need to make sure that we don't make resulting ASTs non-compilable by removing essential information. This is tricky, and it more or less works for TypeTrees, but not for annotations that can contain arbitrary ASTs. For more details look into the comments to Reifiers.scala. * Classfile annotations that contain array arguments and are applied to types, i.e. the ones that generate AnnotatedTypes, cannot be reified. This is because of limitations of manifest infrastructure. Typechecking "Array(mirror.LiteralAnnotArg(...))" would require the compiler to produce a manifest for a path-dependent type, which cannot be done now. Review by @odersky. --- .../scala/reflect/internal/AnnotationInfos.scala | 17 +- .../scala/reflect/internal/Importers.scala | 196 +++-- .../scala/reflect/internal/TreePrinters.scala | 3 + src/compiler/scala/tools/nsc/ast/Reifiers.scala | 969 +++++++++++++-------- .../scala/tools/nsc/ast/ReifyPrinters.scala | 22 +- .../scala/tools/nsc/ast/TreePrinters.scala | 3 - src/compiler/scala/tools/nsc/ast/Trees.scala | 19 - .../scala/tools/nsc/settings/ScalaSettings.scala | 1 + .../scala/tools/nsc/typechecker/Macros.scala | 47 +- .../scala/tools/nsc/typechecker/Typers.scala | 25 +- src/library/scala/reflect/api/Trees.scala | 20 + test/files/neg/reify_ann2a.check | 4 + test/files/neg/reify_ann2a.scala | 30 + test/files/neg/reify_ann2b.check | 7 + test/files/neg/reify_ann2b.scala | 30 + test/files/run/reify_ann1a.check | 30 + test/files/run/reify_ann1a.scala | 30 + test/files/run/reify_ann1b.check | 30 + test/files/run/reify_ann1b.scala | 30 + test/files/run/reify_classfileann_a.check | 18 + test/files/run/reify_classfileann_a.scala | 24 + test/files/run/t5224.check | 9 + test/files/run/t5224.scala | 9 + test/files/run/t5225_1.check | 4 + test/files/run/t5225_1.scala | 7 + test/files/run/t5225_2.check | 4 + test/files/run/t5225_2.scala | 7 + test/files/run/t5419.check | 1 + test/files/run/t5419.scala | 9 + test/pending/run/reify_classfileann_b.check | 0 test/pending/run/reify_classfileann_b.scala | 28 + test/pending/run/t5224.check | 9 - test/pending/run/t5224.scala | 8 - test/pending/run/t5225_1.check | 4 - test/pending/run/t5225_1.scala | 8 - test/pending/run/t5225_2.check | 4 - test/pending/run/t5225_2.scala | 8 - 37 files changed, 1136 insertions(+), 538 deletions(-) create mode 100644 test/files/neg/reify_ann2a.check create mode 100644 test/files/neg/reify_ann2a.scala create mode 100644 test/files/neg/reify_ann2b.check create mode 100644 test/files/neg/reify_ann2b.scala create mode 100644 test/files/run/reify_ann1a.check create mode 100644 test/files/run/reify_ann1a.scala create mode 100644 test/files/run/reify_ann1b.check create mode 100644 test/files/run/reify_ann1b.scala create mode 100644 test/files/run/reify_classfileann_a.check create mode 100644 test/files/run/reify_classfileann_a.scala create mode 100644 test/files/run/t5224.check create mode 100644 test/files/run/t5224.scala create mode 100644 test/files/run/t5225_1.check create mode 100644 test/files/run/t5225_1.scala create mode 100644 test/files/run/t5225_2.check create mode 100644 test/files/run/t5225_2.scala create mode 100644 test/files/run/t5419.check create mode 100644 test/files/run/t5419.scala create mode 100644 test/pending/run/reify_classfileann_b.check create mode 100644 test/pending/run/reify_classfileann_b.scala delete mode 100644 test/pending/run/t5224.check delete mode 100644 test/pending/run/t5224.scala delete mode 100644 test/pending/run/t5225_1.check delete mode 100644 test/pending/run/t5225_1.scala delete mode 100644 test/pending/run/t5225_2.check delete mode 100644 test/pending/run/t5225_2.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/AnnotationInfos.scala b/src/compiler/scala/reflect/internal/AnnotationInfos.scala index c3dde3e6d1..9a7c79d856 100644 --- a/src/compiler/scala/reflect/internal/AnnotationInfos.scala +++ b/src/compiler/scala/reflect/internal/AnnotationInfos.scala @@ -116,6 +116,11 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => // Classfile annot: args empty. Scala annot: assocs empty. assert(args.isEmpty || assocs.isEmpty, atp) + // @xeno.by: necessary for reification, see Reifiers.scala for more info + private var orig: Tree = EmptyTree + def original = orig + def setOriginal(t: Tree): this.type = { orig = t; this } + override def toString = ( atp + (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") + @@ -130,7 +135,7 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => private var forced = false private lazy val forcedInfo = try { - val result = lazyInfo + val result = lazyInfo if (result.pos == NoPosition) result setPos pos result } finally forced = true @@ -138,10 +143,12 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => def atp: Type = forcedInfo.atp def args: List[Tree] = forcedInfo.args def assocs: List[(Name, ClassfileAnnotArg)] = forcedInfo.assocs + def original: Tree = forcedInfo.original + def setOriginal(t: Tree): this.type = { forcedInfo.setOriginal(t); this } // We should always be able to print things without forcing them. override def toString = if (forced) forcedInfo.toString else "@" - + override def pos: Position = if (forced) forcedInfo.pos else NoPosition } @@ -166,10 +173,16 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable => def args: List[Tree] def assocs: List[(Name, ClassfileAnnotArg)] + // @xeno.by: necessary for reification, see Reifiers.scala for more info + def original: Tree + def setOriginal(t: Tree): this.type + /** Hand rolling Product. */ def _1 = atp def _2 = args def _3 = assocs + // @xeno.by: original hasn't become a product member for backward compatibility purposes + // def _4 = original def canEqual(other: Any) = other.isInstanceOf[AnnotationInfo] override def productPrefix = "AnnotationInfo" diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 6c843e6f15..63efaede07 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -9,10 +9,25 @@ trait Importers { self: SymbolTable => val from: SymbolTable lazy val symMap: WeakHashMap[from.Symbol, Symbol] = new WeakHashMap + lazy val tpeMap: WeakHashMap[from.Type, Type] = new WeakHashMap + + // fixups and maps prevent stackoverflows in importer + var pendingSyms = 0 + var pendingTpes = 0 + lazy val fixups = collection.mutable.MutableList[Function0[Unit]]() + def addFixup(fixup: => Unit): Unit = fixups += (() => fixup) + def tryFixup(): Unit = { + if (pendingSyms == 0 && pendingTpes == 0) { + val fixups = this.fixups.toList + this.fixups.clear() + fixups foreach { _() } + } + } object reverse extends from.Importer { val from: self.type = self for ((fromsym, mysym) <- Importer.this.symMap) symMap += ((mysym, fromsym)) + for ((fromtpe, mytpe) <- Importer.this.tpeMap) tpeMap += ((mytpe, fromtpe)) } def importPosition(pos: from.Position): Position = NoPosition @@ -78,7 +93,7 @@ trait Importers { self: SymbolTable => mysym resetFlag Flags.LOCKED } // end doImport - def importOrRelink: Symbol = + def importOrRelink: Symbol = { if (sym == null) null else if (sym == from.NoSymbol) @@ -129,69 +144,103 @@ trait Importers { self: SymbolTable => } else doImport(sym) } - symMap getOrElseUpdate (sym, importOrRelink) + } // end importOrRelink + + if (symMap contains sym) { + symMap(sym) + } else { + pendingSyms += 1 + + try { + symMap getOrElseUpdate (sym, importOrRelink) + } finally { + pendingSyms -= 1 + tryFixup() + } + } } - def importType(tpe: from.Type): Type = tpe match { - case from.TypeRef(pre, sym, args) => - TypeRef(importType(pre), importSymbol(sym), args map importType) - case from.ThisType(clazz) => - ThisType(importSymbol(clazz)) - case from.SingleType(pre, sym) => - SingleType(importType(pre), importSymbol(sym)) - case from.MethodType(params, restpe) => - MethodType(params map importSymbol, importType(restpe)) - case from.PolyType(tparams, restpe) => - PolyType(tparams map importSymbol, importType(restpe)) - case from.NullaryMethodType(restpe) => - NullaryMethodType(importType(restpe)) - case from.ConstantType(constant @ from.Constant(_)) => - ConstantType(importConstant(constant)) - case from.SuperType(thistpe, supertpe) => - SuperType(importType(thistpe), importType(supertpe)) - case from.TypeBounds(lo, hi) => - TypeBounds(importType(lo), importType(hi)) - case from.BoundedWildcardType(bounds) => - BoundedWildcardType(importTypeBounds(bounds)) - case from.ClassInfoType(parents, decls, clazz) => - val myclazz = importSymbol(clazz) - val myscope = if (myclazz.isPackageClass) newPackageScope(myclazz) else newScope - val myclazzTpe = ClassInfoType(parents map importType, myscope, myclazz) - myclazz setInfo polyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope - decls foreach importSymbol // will enter itself into myclazz - myclazzTpe - case from.RefinedType(parents, decls) => - RefinedType(parents map importType, importScope(decls), importSymbol(tpe.typeSymbol)) - case from.ExistentialType(tparams, restpe) => - newExistentialType(tparams map importSymbol, importType(restpe)) - case from.OverloadedType(pre, alts) => - OverloadedType(importType(pre), alts map importSymbol) - case from.AntiPolyType(pre, targs) => - AntiPolyType(importType(pre), targs map importType) - case x: from.TypeVar => - TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) - case from.NotNullType(tpe) => - NotNullType(importType(tpe)) - case from.AnnotatedType(annots, tpe, selfsym) => - AnnotatedType(annots map importAnnotationInfo, importType(tpe), importSymbol(selfsym)) - case from.ErrorType => - ErrorType - case from.WildcardType => - WildcardType - case from.NoType => - NoType - case from.NoPrefix => - NoPrefix - case null => - null + def importType(tpe: from.Type): Type = { + def doImport(tpe: from.Type): Type = tpe match { + case from.TypeRef(pre, sym, args) => + TypeRef(importType(pre), importSymbol(sym), args map importType) + case from.ThisType(clazz) => + ThisType(importSymbol(clazz)) + case from.SingleType(pre, sym) => + SingleType(importType(pre), importSymbol(sym)) + case from.MethodType(params, restpe) => + MethodType(params map importSymbol, importType(restpe)) + case from.PolyType(tparams, restpe) => + PolyType(tparams map importSymbol, importType(restpe)) + case from.NullaryMethodType(restpe) => + NullaryMethodType(importType(restpe)) + case from.ConstantType(constant @ from.Constant(_)) => + ConstantType(importConstant(constant)) + case from.SuperType(thistpe, supertpe) => + SuperType(importType(thistpe), importType(supertpe)) + case from.TypeBounds(lo, hi) => + TypeBounds(importType(lo), importType(hi)) + case from.BoundedWildcardType(bounds) => + BoundedWildcardType(importTypeBounds(bounds)) + case from.ClassInfoType(parents, decls, clazz) => + val myclazz = importSymbol(clazz) + val myscope = if (myclazz.isPackageClass) newPackageScope(myclazz) else newScope + val myclazzTpe = ClassInfoType(parents map importType, myscope, myclazz) + myclazz setInfo polyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope + decls foreach importSymbol // will enter itself into myclazz + myclazzTpe + case from.RefinedType(parents, decls) => + RefinedType(parents map importType, importScope(decls), importSymbol(tpe.typeSymbol)) + case from.ExistentialType(tparams, restpe) => + newExistentialType(tparams map importSymbol, importType(restpe)) + case from.OverloadedType(pre, alts) => + OverloadedType(importType(pre), alts map importSymbol) + case from.AntiPolyType(pre, targs) => + AntiPolyType(importType(pre), targs map importType) + case x: from.TypeVar => + TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol) + case from.NotNullType(tpe) => + NotNullType(importType(tpe)) + case from.AnnotatedType(annots, tpe, selfsym) => + AnnotatedType(annots map importAnnotationInfo, importType(tpe), importSymbol(selfsym)) + case from.ErrorType => + ErrorType + case from.WildcardType => + WildcardType + case from.NoType => + NoType + case from.NoPrefix => + NoPrefix + case null => + null + } // end doImport + + def importOrRelink: Type = + doImport(tpe) + + if (tpeMap contains tpe) { + tpeMap(tpe) + } else { + pendingTpes += 1 + + try { + tpeMap getOrElseUpdate (tpe, importOrRelink) + } finally { + pendingTpes -= 1 + tryFixup() + } + } } def importTypeBounds(bounds: from.TypeBounds) = importType(bounds).asInstanceOf[TypeBounds] - def importAnnotationInfo(ann: from.AnnotationInfo): AnnotationInfo = - AnnotationInfo(importType(ann.atp), ann.args map importTree, ann.assocs map { - case (name, arg) => (importName(name), importAnnotArg(arg)) - }) + def importAnnotationInfo(ann: from.AnnotationInfo): AnnotationInfo = { + val atp1 = importType(ann.atp) + val args1 = ann.args map importTree + val assocs1 = ann.assocs map { case (name, arg) => (importName(name), importAnnotArg(arg)) } + val original1 = importTree(ann.original) + AnnotationInfo(atp1, args1, assocs1) setOriginal original1 + } def importAnnotArg(arg: from.ClassfileAnnotArg): ClassfileAnnotArg = arg match { case from.LiteralAnnotArg(constant @ from.Constant(_)) => @@ -265,6 +314,8 @@ trait Importers { self: SymbolTable => new Function(vparams map importValDef, importTree(body)) case from.Assign(lhs, rhs) => new Assign(importTree(lhs), importTree(rhs)) + case from.AssignOrNamedArg(lhs, rhs) => + new AssignOrNamedArg(importTree(lhs), importTree(rhs)) case from.If(cond, thenp, elsep) => new If(importTree(cond), importTree(thenp), importTree(elsep)) case from.Match(selector, cases) => @@ -326,21 +377,24 @@ trait Importers { self: SymbolTable => case null => null } - if (mytree != null) { - val mysym = if (tree hasSymbol) importSymbol(tree.symbol) else NoSymbol - val mytpe = importType(tree.tpe) + addFixup({ + if (mytree != null) { + val mysym = if (tree hasSymbol) importSymbol(tree.symbol) else NoSymbol + val mytpe = importType(tree.tpe) - mytree match { - case mytt: TypeTree => - val tt = tree.asInstanceOf[from.TypeTree] - if (mytree hasSymbol) mytt.symbol = mysym - if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe) - if (tt.original != null) mytt.setOriginal(importTree(tt.original)) - case _ => - if (mytree hasSymbol) mytree.symbol = importSymbol(tree.symbol) - mytree.tpe = importType(tree.tpe) + mytree match { + case mytt: TypeTree => + val tt = tree.asInstanceOf[from.TypeTree] + if (mytree hasSymbol) mytt.symbol = mysym + if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe) + if (tt.original != null) mytt.setOriginal(importTree(tt.original)) + case _ => + if (mytree hasSymbol) mytree.symbol = importSymbol(tree.symbol) + mytree.tpe = importType(tree.tpe) + } } - } + }) + tryFixup() mytree } diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index e484faff2e..2b1d833c73 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -299,6 +299,9 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => case Assign(lhs, rhs) => print(lhs, " = ", rhs) + case AssignOrNamedArg(lhs, rhs) => + print(lhs, " = ", rhs) + case If(cond, thenp, elsep) => print("if (", cond, ")"); indent; println() print(thenp); undent diff --git a/src/compiler/scala/tools/nsc/ast/Reifiers.scala b/src/compiler/scala/tools/nsc/ast/Reifiers.scala index 105d2cb62b..b82d78b786 100644 --- a/src/compiler/scala/tools/nsc/ast/Reifiers.scala +++ b/src/compiler/scala/tools/nsc/ast/Reifiers.scala @@ -22,278 +22,413 @@ import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } trait Reifiers { self: Global => def reify(tree: Tree): Tree = { - if (tree.tpe != null) { - val saved = printTypings - try { - val reifyDebug = settings.Yreifydebug.value - val debugTrace = util.trace when reifyDebug - debugTrace("transforming = ")(if (settings.Xshowtrees.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) - debugTrace("transformed = ") { - val reifier = new Reifier() - val untyped = reifier.reifyTopLevel(tree) - - val reifyCopypaste = settings.Yreifycopypaste.value - if (reifyCopypaste) { - if (reifyDebug) println("=======================") - println(reifiedNodeToString(untyped)) - if (reifyDebug) println("=======================") - } - - untyped - } - } finally { - printTypings = saved + class Reifier { + import definitions._ + import Reifier._ + + final val scalaPrefix = "scala." + final val localPrefix = "$local" + final val memoizerName = "$memo" + + val reifyDebug = settings.Yreifydebug.value + + private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree + private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms` + private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified + + private def definedInLiftedCode(tpe: Type) = + tpe exists (tp => boundSyms contains tp.typeSymbol) + + private def definedInLiftedCode(sym: Symbol) = + boundSyms contains sym + + /** + * Generate tree of the form + * + * { val $mr = scala.reflect.runtime.Mirror + * $local1 = new TypeSymbol(owner1, NoPosition, name1) + * ... + * $localN = new TermSymbol(ownerN, NoPositiion, nameN) + * $local1.setInfo(tpe1) + * ... + * $localN.setInfo(tpeN) + * $localN.setAnnotations(annotsN) + * rtree + * } + * + * where + * + * - `$localI` are free type symbols in the environment, as well as local symbols + * of refinement types. + * - `tpeI` are the info's of `symI` + * - `rtree` is code that generates `data` at runtime, maintaining all attributes. + * - `data` is typically a tree or a type. + */ + def reifyTopLevel(data: Any): Tree = { + val rtree = reify(data) + Block(mirrorAlias :: reifySymbolTableSetup, rtree) } - } else { - CannotReifyPreTyperTrees(tree) - } - } - - class Reifier() { - import definitions._ - - final val scalaPrefix = "scala." - final val localPrefix = "$local" - final val memoizerName = "$memo" - - val reifyDebug = settings.Yreifydebug.value - - private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree - private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms` - private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified - - /** - * Generate tree of the form - * - * { val $mr = scala.reflect.runtime.Mirror - * $local1 = new TypeSymbol(owner1, NoPosition, name1) - * ... - * $localN = new TermSymbol(ownerN, NoPositiion, nameN) - * $local1.setInfo(tpe1) - * ... - * $localN.setInfo(tpeN) - * $localN.setAnnotations(annotsN) - * rtree - * } - * - * where - * - * - `$localI` are free type symbols in the environment, as well as local symbols - * of refinement types. - * - `tpeI` are the info's of `symI` - * - `rtree` is code that generates `data` at runtime, maintaining all attributes. - * - `data` is typically a tree or a type. - */ - def reifyTopLevel(data: Any): Tree = { - val rtree = reify(data) - Block(mirrorAlias :: reifySymbolTableSetup, rtree) - } - private def isLocatable(sym: Symbol) = - sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0 + private def isLocatable(sym: Symbol) = + sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0 - private def registerReifiableSymbol(sym: Symbol): Unit = - if (!(symIndex contains sym)) { - sym.owner.ownersIterator find (x => !isLocatable(x)) foreach registerReifiableSymbol - symIndex(sym) = reifiableSyms.length - reifiableSyms += sym - } + private def registerReifiableSymbol(sym: Symbol): Unit = + if (!(symIndex contains sym)) { + sym.owner.ownersIterator find (x => !isLocatable(x)) foreach registerReifiableSymbol + symIndex(sym) = reifiableSyms.length + reifiableSyms += sym + } - // helper methods - - private def localName(sym: Symbol): TermName = - newTermName(localPrefix + symIndex(sym)) - - private def call(fname: String, args: Tree*): Tree = - Apply(termPath(fname), args.toList) - - private def mirrorSelect(name: String): Tree = - termPath(nme.MIRROR_PREFIX + name) - - private def mirrorCall(name: TermName, args: Tree*): Tree = - call("" + (nme.MIRROR_PREFIX append name), args: _*) - - private def mirrorCall(name: String, args: Tree*): Tree = - call(nme.MIRROR_PREFIX + name, args: _*) - - private def mirrorFactoryCall(value: Product, args: Tree*): Tree = - mirrorCall(value.productPrefix, args: _*) - - private def scalaFactoryCall(name: String, args: Tree*): Tree = - call(scalaPrefix + name + ".apply", args: _*) - - private def mkList(args: List[Tree]): Tree = - scalaFactoryCall("collection.immutable.List", args: _*) - - private def reifyModifiers(m: Modifiers) = - mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations)) - - private def reifyAggregate(name: String, args: Any*) = - scalaFactoryCall(name, (args map reify).toList: _*) - - /** - * Reify a list - */ - private def reifyList(xs: List[Any]): Tree = - mkList(xs map reify) - - /** Reify a name */ - private def reifyName(name: Name) = - mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString))) - - private def isFree(sym: Symbol) = - !(symIndex contains sym) - - /** - * Reify a reference to a symbol - */ - private def reifySymRef(sym: Symbol): Tree = { - symIndex get sym match { - case Some(idx) => - Ident(localName(sym)) - case None => - if (sym == NoSymbol) - mirrorSelect("NoSymbol") - else if (sym == RootPackage) - mirrorSelect("definitions.RootPackage") - else if (sym == RootClass) - mirrorSelect("definitions.RootClass") - else if (sym == EmptyPackage) - mirrorSelect("definitions.EmptyPackage") - else if (sym.isModuleClass) - Select(reifySymRef(sym.sourceModule), "moduleClass") - else if (sym.isStatic && sym.isClass) - mirrorCall("staticClass", reify(sym.fullName)) - else if (sym.isStatic && sym.isModule) - mirrorCall("staticModule", reify(sym.fullName)) - else if (isLocatable(sym)) - if (sym.isTypeParameter) - mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos)) + // helper methods + + private def localName(sym: Symbol): TermName = + newTermName(localPrefix + symIndex(sym)) + + private def call(fname: String, args: Tree*): Tree = + Apply(termPath(fname), args.toList) + + private def mirrorSelect(name: String): Tree = + termPath(nme.MIRROR_PREFIX + name) + + private def mirrorCall(name: TermName, args: Tree*): Tree = + call("" + (nme.MIRROR_PREFIX append name), args: _*) + + private def mirrorCall(name: String, args: Tree*): Tree = + call(nme.MIRROR_PREFIX + name, args: _*) + + private def mirrorFactoryCall(value: Product, args: Tree*): Tree = + mirrorFactoryCall(value.productPrefix, args: _*) + + private def mirrorFactoryCall(prefix: String, args: Tree*): Tree = + mirrorCall(prefix, args: _*) + + private def scalaFactoryCall(name: String, args: Tree*): Tree = + call(scalaPrefix + name + ".apply", args: _*) + + private def mkList(args: List[Tree]): Tree = + scalaFactoryCall("collection.immutable.List", args: _*) + + private def reifyModifiers(m: Modifiers) = + mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations)) + + private def reifyAggregate(name: String, args: Any*) = + scalaFactoryCall(name, (args map reify).toList: _*) + + /** + * Reify a list + */ + private def reifyList(xs: List[Any]): Tree = + mkList(xs map reify) + + /** + * Reify an array + */ + private def reifyArray(xs: Array[_]): Tree = + // @xeno.by: doesn't work for Array(LiteralAnnotArg(...)) + // because we cannot generate manifests for path-dependent types + scalaFactoryCall(nme.Array, xs map reify: _*) + + /** Reify a name */ + private def reifyName(name: Name) = + mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString))) + + private def isFree(sym: Symbol) = + !(symIndex contains sym) + + /** + * Reify a reference to a symbol + */ + private def reifySymRef(sym: Symbol): Tree = { + symIndex get sym match { + case Some(idx) => + Ident(localName(sym)) + case None => + if (sym == NoSymbol) + mirrorSelect("NoSymbol") + else if (sym == RootPackage) + mirrorSelect("definitions.RootPackage") + else if (sym == RootClass) + mirrorSelect("definitions.RootClass") + else if (sym == EmptyPackage) + mirrorSelect("definitions.EmptyPackage") + else if (sym.isModuleClass) + Select(reifySymRef(sym.sourceModule), "moduleClass") + else if (sym.isStatic && sym.isClass) + mirrorCall("staticClass", reify(sym.fullName)) + else if (sym.isStatic && sym.isModule) + mirrorCall("staticModule", reify(sym.fullName)) + else if (isLocatable(sym)) + if (sym.isTypeParameter) + mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos)) + else { + if (reifyDebug) println("locatable: " + sym + " " + sym.isPackageClass + " " + sym.owner + " " + sym.isTypeParameter) + val rowner = reify(sym.owner) + val rname = reify(sym.name.toString) + if (sym.isType) + mirrorCall("selectType", rowner, rname) + else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) { + val index = sym.owner.info.decl(sym.name).alternatives indexOf sym + assert(index >= 0, sym) + mirrorCall("selectOverloadedMethod", rowner, rname, reify(index)) + } else + mirrorCall("selectTerm", rowner, rname) + } else { - if (reifyDebug) println("locatable: " + sym + " " + sym.isPackageClass + " " + sym.owner + " " + sym.isTypeParameter) - val rowner = reify(sym.owner) - val rname = reify(sym.name.toString) - if (sym.isType) - mirrorCall("selectType", rowner, rname) - else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) { - val index = sym.owner.info.decl(sym.name).alternatives indexOf sym - assert(index >= 0, sym) - mirrorCall("selectOverloadedMethod", rowner, rname, reify(index)) - } else - mirrorCall("selectTerm", rowner, rname) - } - else { - if (sym.isTerm) { - if (reifyDebug) println("Free: " + sym) - val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false) - def markIfCaptured(arg: Ident): Tree = - if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg - mirrorCall("newFreeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym))) - } else { - if (reifyDebug) println("Late local: " + sym) - registerReifiableSymbol(sym) - reifySymRef(sym) + if (sym.isTerm) { + if (reifyDebug) println("Free: " + sym) + val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false) + def markIfCaptured(arg: Ident): Tree = + if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg + mirrorCall("newFreeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym))) + } else { + if (reifyDebug) println("Late local: " + sym) + registerReifiableSymbol(sym) + reifySymRef(sym) + } } - } + } } - } - /** - * reify the creation of a symbol - */ - private def reifySymbolDef(sym: Symbol): Tree = { - if (reifyDebug) println("reify sym def " + sym) - - ValDef(NoMods, localName(sym), TypeTree(), - Apply( - Select(reify(sym.owner), "newNestedSymbol"), - List(reify(sym.name), reify(sym.pos), Literal(Constant(sym.flags))) + /** + * reify the creation of a symbol + */ + private def reifySymbolDef(sym: Symbol): Tree = { + if (reifyDebug) println("reify sym def " + sym) + + ValDef(NoMods, localName(sym), TypeTree(), + Apply( + Select(reify(sym.owner), "newNestedSymbol"), + List(reify(sym.name), reify(sym.pos), Literal(Constant(sym.flags))) + ) ) - ) - } + } - /** - * Generate code to add type and annotation info to a reified symbol - */ - private def fillInSymbol(sym: Symbol): Tree = { - val rset = Apply(Select(reifySymRef(sym), nme.setTypeSignature), List(reifyType(sym.info))) - if (sym.annotations.isEmpty) rset - else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations))) - } + /** + * Generate code to add type and annotation info to a reified symbol + */ + private def fillInSymbol(sym: Symbol): Tree = { + val rset = Apply(Select(reifySymRef(sym), nme.setTypeSignature), List(reifyType(sym.info))) + if (sym.annotations.isEmpty) rset + else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations))) + } - /** Reify a scope */ - private def reifyScope(scope: Scope): Tree = { - scope foreach registerReifiableSymbol - mirrorCall(nme.newScopeWith, scope.toList map reifySymRef: _*) - } + /** Reify a scope */ + private def reifyScope(scope: Scope): Tree = { + scope foreach registerReifiableSymbol + mirrorCall(nme.newScopeWith, scope.toList map reifySymRef: _*) + } - /** Reify a list of symbols that need to be created */ - private def reifySymbols(syms: List[Symbol]): Tree = { - syms foreach registerReifiableSymbol - mkList(syms map reifySymRef) - } + /** Reify a list of symbols that need to be created */ + private def reifySymbols(syms: List[Symbol]): Tree = { + syms foreach registerReifiableSymbol + mkList(syms map reifySymRef) + } - /** Reify a type that defines some symbols */ - private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree = - mirrorFactoryCall(value, reifySymbols(bound), reify(underlying)) - - /** Reify a type */ - private def reifyType(tpe0: Type): Tree = { - val tpe = tpe0.normalize - val tsym = tpe.typeSymbol - if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) - Select(reifySymRef(tpe.typeSymbol), nme.asTypeConstructor) - else tpe match { - case t @ NoType => - reifyMirrorObject(t) - case t @ NoPrefix => - reifyMirrorObject(t) - case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic => - mirrorCall(nme.thisModuleType, reify(clazz.fullName)) - case t @ RefinedType(parents, decls) => - registerReifiableSymbol(tpe.typeSymbol) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ClassInfoType(parents, decls, clazz) => - registerReifiableSymbol(clazz) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ExistentialType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ PolyType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ MethodType(params, restpe) => - reifyTypeBinder(t, params, restpe) - case _ => - reifyProductUnsafe(tpe) + /** Reify a type that defines some symbols */ + private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree = + mirrorFactoryCall(value, reifySymbols(bound), reify(underlying)) + + /** Reify a type */ + private def reifyType(tpe0: Type): Tree = { + val tpe = tpe0.normalize + + if (tpe.isErroneous) + CannotReifyErroneousType(tpe) + if (definedInLiftedCode(tpe)) + CannotReifyTypeInvolvingBoundType(tpe) + + val tsym = tpe.typeSymbol + if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) + Select(reifySymRef(tpe.typeSymbol), nme.asTypeConstructor) + else tpe match { + case t @ NoType => + reifyMirrorObject(t) + case t @ NoPrefix => + reifyMirrorObject(t) + case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic => + mirrorCall(nme.thisModuleType, reify(clazz.fullName)) + case t @ RefinedType(parents, decls) => + registerReifiableSymbol(tpe.typeSymbol) + mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) + case t @ ClassInfoType(parents, decls, clazz) => + registerReifiableSymbol(clazz) + mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) + case t @ ExistentialType(tparams, underlying) => + reifyTypeBinder(t, tparams, underlying) + case t @ PolyType(tparams, underlying) => + reifyTypeBinder(t, tparams, underlying) + case t @ MethodType(params, restpe) => + reifyTypeBinder(t, params, restpe) + case t @ AnnotatedType(anns, underlying, selfsym) => + val saved1 = reifySymbols + val saved2 = reifyTypes + + try { + // one more quirk of reifying annotations + // + // when reifying AnnotatedTypes we need to reify all the types and symbols of inner ASTs + // that's because a lot of logic expects post-typer trees to have non-null tpes + // + // Q: reified trees are pre-typer, so there's shouldn't be a problem. + // reflective typechecker will fill in missing symbols and types, right? + // A: actually, no. annotation ASTs live inside AnnotatedTypes, + // and insides of the types is the place where typechecker doesn't look. + reifySymbols = true + reifyTypes = true + if (reifyDebug) println("reify AnnotatedType: " + tpe) + reifyProductUnsafe(tpe) + } finally { + reifySymbols = saved1 + reifyTypes = saved2 + } + case _ => + reifyProductUnsafe(tpe) + } } - } - private def definedInLiftedCode(tpe: Type) = - tpe exists (tp => boundSyms contains tp.typeSymbol) + var reifySymbols = false + var reifyTypes = false + + /** Reify a tree */ + private def reifyTree(tree: Tree): Tree = { + def reifyDefault(tree: Tree) = + reifyProduct(tree) + + var rtree = tree match { + case tree if tree.isErroneous => + CannotReifyErroneousTree(tree) + case self.EmptyTree => + reifyMirrorObject(EmptyTree) + case self.emptyValDef => + mirrorSelect(nme.emptyValDef) + case This(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) => + reifyFree(tree) + case Ident(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) => + if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { + if (reifyDebug) println("captured variable: " + tree.symbol) + captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here. + mirrorCall("Select", reifyFree(tree), reifyName(nme.elem)) + } else reifyFree(tree) + case tt: TypeTree if (tt.tpe != null) => + reifyTypeTree(tt) + case ta @ TypeApply(hk, ts) => + def isErased(tt: TypeTree) = tt.tpe != null && definedInLiftedCode(tt.tpe) && tt.original == null + val discard = ts collect { case tt: TypeTree => tt } exists isErased + if (reifyDebug && discard) println("discarding TypeApply: " + tree) + if (discard) reifyTree(hk) else reifyDefault(ta) + case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) => + CannotReifyClassOfBoundType(tree, tpe) + case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym => + CannotReifyClassOfBoundEnum(tree, constant.tpe) + case tree if tree.isDef => + if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt } headOption).getOrElse(TypeTree(tree.tpe)))) + // registerReifiableSymbol(tree.symbol) + boundSyms += tree.symbol + + val prefix = tree.productPrefix + val elements = (tree.productIterator map { + // annotations exist in two flavors: + // 1) pre-typer ones that populate: a) Modifiers, b) Annotated nodes (irrelevant in this context) + // 2) post-typer ones that dwell inside: a) sym.annotations, b) AnnotatedTypes (irrelevant in this context) + // + // here we process Modifiers that are involved in deftrees + // AnnotatedTypes get reified elsewhere (currently, in ``reifyTypeTree'') + case Modifiers(flags, privateWithin, annotations) => + assert(annotations.isEmpty) // should've been eliminated by the typer + val postTyper = tree.symbol.annotations filter (_.original != EmptyTree) + if (reifyDebug && !postTyper.isEmpty) println("reify symbol annotations for %s: %s".format(tree.symbol, tree.symbol.annotations)) + val preTyper = postTyper map toPreTyperAnnotation + Modifiers(flags, privateWithin, preTyper) + case x => + x + }).toList + reifyProduct(prefix, elements) + case _ => + reifyDefault(tree) + } - private def isErased(tree: Tree) = tree match { - case tt: TypeTree => definedInLiftedCode(tt.tpe) && tt.original == null - case _ => false - } + // usually we don't reify symbols/types, because they can be re-inferred during subsequent reflective compilation + // however, reification of AnnotatedTypes is special. see ``reifyType'' to find out why. + if (reifySymbols && tree.hasSymbol) { + if (reifyDebug) println("reifying symbol %s for tree %s".format(tree.symbol, tree)) + rtree = Apply(Select(rtree, nme.setSymbol), List(reifySymRef(tree.symbol))) + } + if (reifyTypes && tree.tpe != null) { + if (reifyDebug) println("reifying type %s for tree %s".format(tree.tpe, tree)) + rtree = Apply(Select(rtree, nme.setType), List(reifyType(tree.tpe))) + } - /** Reify a tree */ - private def reifyTree(tree: Tree): Tree = tree match { - case EmptyTree => - reifyMirrorObject(EmptyTree) - case This(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) => - reifyFree(tree) - case Ident(_) if tree.symbol != NoSymbol && !(boundSyms contains tree.symbol) => - if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { - captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here. - mirrorCall("Select", reifyFree(tree), reifyName(nme.elem)) - } else reifyFree(tree) - case tt: TypeTree if (tt.tpe != null) => + rtree + } + + /** Reify pre-typer representation of a type. + * + * NB: This is the trickiest part of reification! + * + * In most cases, we're perfectly fine to reify a Type itself (see ``reifyType''). + * However if the type involves a symbol declared inside the quasiquote (i.e. registered in ``boundSyms''), + * then we cannot reify it, or otherwise subsequent reflective compilation will fail. + * + * Why will it fail? Because reified deftrees (e.g. ClassDef(...)) will generate fresh symbols during that compilation, + * so naively reified symbols will become out of sync, which brings really funny compilation errors and/or crashes, e.g.: + * https://issues.scala-lang.org/browse/SI-5230 + * + * To deal with this unpleasant fact, we need to fall back from types to equivalent trees (after all, parser trees don't contain any types, just trees, so it should be possible). + * Luckily, these original trees get preserved for us in the ``original'' field when Trees get transformed into TypeTrees. + * And if an original of a type tree is empty, we can safely assume that this type is non-essential (e.g. was inferred/generated by the compiler). + * In that case the type can be omitted (e.g. reified as an empty TypeTree), since it will be inferred again later on. + * + * An important property of the original is that it isn't just a pre-typer tree. + * It's actually kind of a post-typer tree with symbols assigned to its Idents (e.g. Ident("List") will contain a symbol that points to immutable.this.List). + * This is very important, since subsequent reflective compilation won't have to resolve these symbols. + * In general case, such resolution cannot be performed, since reification doesn't preserve lexical context, + * which means that reflective compilation won't be aware of, say, imports that were provided when the reifee has been compiled. + * + * This workaround worked surprisingly well and allowed me to fix several important reification bugs, until the abstraction has leaked. + * Suddenly I found out that in certain contexts original trees do not contain symbols, but are just parser trees. + * To the moment I know two such situations: + * 1) Unapplies: https://issues.scala-lang.org/browse/SI-5273?focusedCommentId=56057#comment-56057 + * 2) Annotations: typedAnnotations does not typecheck the annotation in-place, but rather creates new trees and typechecks them, so the original remains symless + * 3) + */ + private def reifyTypeTree(tt: TypeTree): Tree = { if (definedInLiftedCode(tt.tpe)) { - // erase non-essential (i.e. inferred) types - // reify symless counterparts of essential types - // @xeno.by: in general case reflective compiler lacks the context to typecheck the originals - // more info here: https://issues.scala-lang.org/browse/SI-5273?focusedCommentId=56057#comment-56057 - // this is A BIG BAD TODO! - if (tt.original != null) reify(tt.original) else mirrorCall("TypeTree") + if (reifyDebug) println("reifyTypeTree, defined in lifted code: " + tt.tpe) + if (tt.original != null) { + val annotations = tt.tpe filter { _.isInstanceOf[AnnotatedType] } collect { case atp: AnnotatedType => atp.annotations } flatten + val annmap = annotations map { ann => (ann.original, ann) } toMap + + // annotations exist in two flavors: + // 1) pre-typer ones that populate: a) Modifiers (irrelevant in this context), b) Annotated nodes + // 2) post-typer ones that dwell inside: a) sym.annotations (irrelevant in this context), b) AnnotatedTypes + // + // here we process AnnotatedTypes, since only they can be involved in TypeTrees + // Modifiers get reified elsewhere (currently, in the "isDef" case of ``reifyTree'') + // + // the problem with annotations is that their originals don't preserve any symbols at all + // read the comment to this method to find out why it's bad + // that's why we transplant typechecked, i.e. symful, annotations onto original trees + class AnnotationFixup extends self.Transformer { + override def transform(tree: Tree) = tree match { + case Annotated(ann0, args) => + assert(annmap contains ann0) + val ann1 = annmap(ann0) + val ann = toPreTyperAnnotation(ann1) + Annotated(ann, transform(args)) + case _ => + tree + } + } + + if (reifyDebug) println("verdict: essential, reify as original") + val patchedOriginal = new AnnotationFixup().transform(tt.original) + reifyTree(patchedOriginal) + } else { + // type is deemed to be non-essential + // erase it and hope that subsequent reflective compilation will be able to recreate it again + if (reifyDebug) println("verdict: non-essential, discard") + mirrorCall("TypeTree") + } } else { var rtt = mirrorCall(nme.TypeTree, reifyType(tt.tpe)) // @xeno.by: originals get typechecked during subsequent reflective compilation, which leads to subtle bugs @@ -306,124 +441,219 @@ trait Reifiers { self: Global => // } rtt } - case ta @ TypeApply(hk, ts) => - if (ts exists isErased) reifyTree(hk) else reifyProduct(ta) - case self.emptyValDef => - mirrorSelect(nme.emptyValDef) - case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) => - CannotReifyClassOfBoundType(tree, tpe) - case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym => - CannotReifyClassOfBoundEnum(tree, constant.tpe) - case _ => - if (tree.isDef) { - if (reifyDebug) println("boundSym: " + tree.symbol) - boundSyms += tree.symbol + } + + /** Reify post-typer representation of an annotation */ + private def reifyAnnotation(ann: AnnotationInfo): Tree = + // @xeno.by: if you reify originals, you get SO when trying to reify AnnotatedTypes, so screw it - after all, it's not that important + mirrorFactoryCall("AnnotationInfo", reifyType(ann.atp), reifyList(ann.args), reify(ann.assocs)) + + /** Reify pre-typer representation of an annotation. + * The trick here is to retain the symbols that have been populated during typechecking of the annotation. + * If we do not do that, subsequent reflective compilation will fail. + */ + private def toPreTyperAnnotation(ann: AnnotationInfo): Tree = { + if (definedInLiftedCode(ann.atp)) { + // todo. deconstruct reifiable tree from ann.original and ann.args+ann.assocs + // + // keep in mind that we can't simply use ann.original, because its args are symless + // which means that any imported symbol (e.g. List) will crash subsequent reflective compilation + // hint: if I had enough time, I'd try to extract reifiable annotation type from ann.original + // and to apply its constructor to ann.args (that are symful, i.e. suitable for reification) + // + // also, if we pursue the route of reifying annotations defined in lifted code + // we should think about how to provide types for all nodes of the return value + // this will be necessary for reifying AnnotatedTypes, since ASTs inside ATs must all have non-null tpes + // an alternative would be downgrading ATs to Annotated nodes, but this needs careful thinking + // for now I just leave this as an implementation restriction + CannotReifyAnnotationInvolvingBoundType(ann) + } else { + val args = if (ann.assocs.isEmpty) { + ann.args + } else { + def toScalaAnnotation(jann: ClassfileAnnotArg): Tree = jann match { + case LiteralAnnotArg(const) => + Literal(const) + case ArrayAnnotArg(arr) => + Apply(Ident(definitions.ArrayModule), arr.toList map toScalaAnnotation) + case NestedAnnotArg(ann) => + toPreTyperAnnotation(ann) + } + + ann.assocs map { case (nme, arg) => AssignOrNamedArg(Ident(nme), toScalaAnnotation(arg)) } + } + + New(TypeTree(ann.atp), List(args)) + } + } + + /** + * Reify a free reference. The result will be either a mirror reference + * to a global value, or else a mirror Literal. + */ + private def reifyFree(tree: Tree): Tree = tree match { + case This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass => + val sym = tree.symbol + if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) + if (reifyDebug) println("Free: " + sym) + val freeVar = mirrorCall("newFreeVar", reify(sym.name.toString), reify(sym.tpe), This(sym)) + mirrorCall(nme.Ident, freeVar) + case This(_) => + if (reifyDebug) println("This for %s, reified as This".format(tree.symbol)) + mirrorCall(nme.This, reifySymRef(tree.symbol)) + case _ => + mirrorCall(nme.Ident, reifySymRef(tree.symbol)) + } + + // todo: consider whether we should also reify positions + private def reifyPosition(pos: Position): Tree = + reifyMirrorObject(NoPosition) + + // !!! we must eliminate these casts. + private def reifyProductUnsafe(x: Any): Tree = + if (x.isInstanceOf[Product]) reifyProduct(x.asInstanceOf[Product]) + else throw new Exception("%s of type %s cannot be cast to Product".format(x, x.getClass)) + private def reifyProduct(x: Product): Tree = + reifyProduct(x.productPrefix, x.productIterator.toList) + private def reifyProduct(prefix: String, elements: List[Any]): Tree = { + // @xeno.by: reflection would be more robust, but, hey, this is a hot path + if (prefix.startsWith("Tuple")) reifyAggregate(prefix, elements: _*) + else mirrorCall(prefix, (elements map reify): _*) + } + + /** + * Reify a case object defined in Mirror + */ + private def reifyMirrorObject(name: String): Tree = mirrorSelect(name) + private def reifyMirrorObject(x: Product): Tree = reifyMirrorObject(x.productPrefix) + + private def isReifiableConstant(value: Any) = value match { + case null => true // seems pretty reifable to me? + case _: String => true + case _ => isAnyVal(value) + } + + /** Reify an arbitary value */ + private def reify(value: Any): Tree = value match { + case tree: Tree => reifyTree(tree) + case sym: Symbol => reifySymRef(sym) + case tpe: Type => reifyType(tpe) + case xs: List[_] => reifyList(xs) + case xs: Array[_] => reifyArray(xs) + case scope: Scope => reifyScope(scope) + case x: Name => reifyName(x) + case x: Position => reifyPosition(x) + case x: Modifiers => reifyModifiers(x) + case x: AnnotationInfo => reifyAnnotation(x) + case _ => + if (isReifiableConstant(value)) Literal(Constant(value)) + else reifyProductUnsafe(value) + } + + /** + * An (unreified) path that refers to definition with given fully qualified name + * @param mkName Creator for last portion of name (either TermName or TypeName) + */ + private def path(fullname: String, mkName: String => Name): Tree = { + val parts = fullname split "\\." + val prefixParts = parts.init + val lastName = mkName(parts.last) + if (prefixParts.isEmpty) Ident(lastName) + else { + val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _)) + Select(prefixTree, lastName) + } + } + + /** An (unreified) path that refers to term definition with given fully qualified name */ + private def termPath(fullname: String): Tree = path(fullname, newTermName) + + /** An (unreified) path that refers to type definition with given fully qualified name */ + private def typePath(fullname: String): Tree = path(fullname, newTypeName) + + private def mirrorAlias = + ValDef(NoMods, nme.MIRROR_SHORT, SingletonTypeTree(termPath(fullnme.MirrorPackage)), termPath(fullnme.MirrorPackage)) + + /** + * Generate code that generates a symbol table of all symbols registered in `reifiableSyms` + */ + private def reifySymbolTableSetup: List[Tree] = { + val symDefs, fillIns = new mutable.ArrayBuffer[Tree] + var i = 0 + while (i < reifiableSyms.length) { + // fillInSymbol might create new reifiableSyms, that's why this is done iteratively + symDefs += reifySymbolDef(reifiableSyms(i)) + fillIns += fillInSymbol(reifiableSyms(i)) + i += 1 } - reifyProduct(tree) - /* - if (tree.isDef || tree.isInstanceOf[Function]) - registerReifiableSymbol(tree.symbol) - if (tree.hasSymbol) - rtree = Apply(Select(rtree, nme.setSymbol), List(reifySymRef(tree.symbol))) - Apply(Select(rtree, nme.setType), List(reifyType(tree.tpe))) -*/ - } + symDefs.toList ++ fillIns.toList + } + } // end of Reifier - /** - * Reify a free reference. The result will be either a mirror reference - * to a global value, or else a mirror Literal. - */ - private def reifyFree(tree: Tree): Tree = tree match { - case This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass => - val sym = tree.symbol - if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) - if (reifyDebug) println("Free: " + sym) - val freeVar = mirrorCall("newFreeVar", reify(sym.name.toString), reify(sym.tpe), This(sym)) - mirrorCall(nme.Ident, freeVar) - case This(_) => - if (reifyDebug) println("This for %s, reified as This".format(tree.symbol)) - mirrorCall(nme.This, reifySymRef(tree.symbol)) - case _ => - mirrorCall(nme.Ident, reifySymRef(tree.symbol)) - } + object Reifier { + def CannotReifyPreTyperTree(tree: Tree) = { + val msg = "pre-typer trees are not supported, consider typechecking the tree before passing it to the reifier" + throw new ReifierError(tree.pos, msg) + } - // todo: consider whether we should also reify positions - private def reifyPosition(pos: Position): Tree = - reifyMirrorObject(NoPosition) - - // !!! we must eliminate these casts. - private def reifyProductUnsafe(x: Any): Tree = - reifyProduct(x.asInstanceOf[Product]) - private def reifyProduct(x: Product): Tree = - mirrorCall(x.productPrefix, (x.productIterator map reify).toList: _*) - - /** - * Reify a case object defined in Mirror - */ - private def reifyMirrorObject(name: String): Tree = mirrorSelect(name) - private def reifyMirrorObject(x: Product): Tree = reifyMirrorObject(x.productPrefix) - - private def isReifiableConstant(value: Any) = value match { - case null => true // seems pretty reifable to me? - case _: String => true - case _ => isAnyVal(value) - } + def CannotReifyErroneousTree(tree: Tree) = { + val msg = "erroneous trees are not supported, make sure that your tree typechecks successfully before passing it to the reifier" + throw new ReifierError(tree.pos, msg) + } - /** Reify an arbitary value */ - private def reify(value: Any): Tree = value match { - case tree: Tree => reifyTree(tree) - case sym: Symbol => reifySymRef(sym) - case tpe: Type => reifyType(tpe) - case xs: List[_] => reifyList(xs) - case xs: Array[_] => scalaFactoryCall(nme.Array, xs map reify: _*) - case scope: Scope => reifyScope(scope) - case x: Name => reifyName(x) - case x: Position => reifyPosition(x) - case x: Modifiers => reifyModifiers(x) - case _ => - if (isReifiableConstant(value)) Literal(Constant(value)) - else reifyProductUnsafe(value) - } + def CannotReifyErroneousType(tpe: Type) = { + val msg = "erroneous types are not supported, make sure that your tree typechecks successfully before passing it to the reifier" + throw new ReifierError(NoPosition, msg) + } - /** - * An (unreified) path that refers to definition with given fully qualified name - * @param mkName Creator for last portion of name (either TermName or TypeName) - */ - private def path(fullname: String, mkName: String => Name): Tree = { - val parts = fullname split "\\." - val prefixParts = parts.init - val lastName = mkName(parts.last) - if (prefixParts.isEmpty) Ident(lastName) - else { - val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _)) - Select(prefixTree, lastName) + def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = { + val msg = "implementation restriction: cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe) + throw new ReifierError(tree.pos, msg) + } + + def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = { + val msg = "implementation restriction: cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe) + throw new ReifierError(tree.pos, msg) + } + + def CannotReifyTypeInvolvingBoundType(tpe: Type) = { + val msg = "implementation restriction: cannot reify type %s which involves a symbol declared inside the block being reified".format(tpe) + throw new ReifierError(NoPosition, msg) } - } - /** An (unreified) path that refers to term definition with given fully qualified name */ - private def termPath(fullname: String): Tree = path(fullname, newTermName) - - /** An (unreified) path that refers to type definition with given fully qualified name */ - private def typePath(fullname: String): Tree = path(fullname, newTypeName) - - private def mirrorAlias = - ValDef(NoMods, nme.MIRROR_SHORT, SingletonTypeTree(termPath(fullnme.MirrorPackage)), termPath(fullnme.MirrorPackage)) - - /** - * Generate code that generates a symbol table of all symbols registered in `reifiableSyms` - */ - private def reifySymbolTableSetup: List[Tree] = { - val symDefs, fillIns = new mutable.ArrayBuffer[Tree] - var i = 0 - while (i < reifiableSyms.length) { - // fillInSymbol might create new reifiableSyms, that's why this is done iteratively - symDefs += reifySymbolDef(reifiableSyms(i)) - fillIns += fillInSymbol(reifiableSyms(i)) - i += 1 + def CannotReifyAnnotationInvolvingBoundType(ann: AnnotationInfo) = { + val msg = "implementation restriction: cannot reify annotation @%s which involves a symbol declared inside the block being reified".format(ann) + throw new ReifierError(ann.original.pos, msg) } + } // end of Reifier + + // begin reify + import Reifier._ + if (tree.tpe != null) { + val saved = printTypings + try { + val reifyDebug = settings.Yreifydebug.value + val debugTrace = util.trace when reifyDebug + debugTrace("transforming = ")(if (settings.Xshowtrees.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) + debugTrace("transformed = ") { + val reifier = new Reifier() + val untyped = reifier.reifyTopLevel(tree) + + val reifyCopypaste = settings.Yreifycopypaste.value + if (reifyCopypaste) { + if (reifyDebug) println("=======================") + println(reifiedNodeToString(untyped)) + if (reifyDebug) println("=======================") + } - symDefs.toList ++ fillIns.toList + untyped + } + } finally { + printTypings = saved + } + } else { + CannotReifyPreTyperTree(tree) } } @@ -431,19 +661,4 @@ trait Reifiers { self: Global => class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) { def this(msg: String) = this(NoPosition, msg) } - - def CannotReifyPreTyperTrees(tree: Tree) = { - val msg = "pre-typer trees are not supported, consider typechecking the tree before passing it to the reifier" - throw new ReifierError(tree.pos, msg) - } - - def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = { - val msg = "cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe) - throw new ReifierError(tree.pos, msg) - } - - def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = { - val msg = "cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe) - throw new ReifierError(tree.pos, msg) - } } diff --git a/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala index 98135fadda..fce59bb099 100644 --- a/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/ReifyPrinters.scala @@ -34,22 +34,22 @@ trait ReifyPrinters { self: NodePrinters => s = s.replace("modifiersFromInternalFlags", "Modifiers") s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()") s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => { - val buf = new StringBuilder + val buf = new collection.mutable.ListBuffer[String] - val flags = m.group(1).toLong - val s_flags = Flags.modifiersOfFlags(flags) map (_.sourceString) mkString ", " - if (s_flags != "") - buf.append("Set(" + s_flags + ")") + val annotations = m.group(3) + if (buf.nonEmpty || annotations.nonEmpty) + buf.append("List(" + annotations + ")") val privateWithin = "" + m.group(2) - if (privateWithin != "") - buf.append(", newTypeName(\"" + privateWithin + "\")") + if (buf.nonEmpty || privateWithin != "") + buf.append("newTypeName(\"" + privateWithin + "\")") - val annotations = m.group(3) - if (annotations.nonEmpty) - buf.append(", List(" + annotations + ")") + val flags = m.group(1).toLong + val s_flags = Flags.modifiersOfFlags(flags) map (_.sourceString) mkString ", " + if (buf.nonEmpty || s_flags != "") + buf.append("Set(" + s_flags + ")") - "Modifiers(" + buf.toString + ")" + "Modifiers(" + buf.reverse.mkString(", ") + ")" }) s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => { val flags = m.group(1).toLong diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index c060e938bb..3371353f25 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -51,9 +51,6 @@ trait TreePrinters extends reflect.internal.TreePrinters { this: Global => treePrinter.println() treePrinter.print(definition) - case AssignOrNamedArg(lhs, rhs) => - treePrinter.print(lhs, " = ", rhs) - case TypeTreeWithDeferredRefCheck() => treePrinter.print("") diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 83b6252b26..9e304a0eb5 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -30,12 +30,6 @@ trait Trees extends reflect.internal.Trees { self: Global => override def isType = definition.isType } - /** Either an assignment or a named argument. Only appears in argument lists, - * eliminated by typecheck (doTypedApply) - */ - case class AssignOrNamedArg(lhs: Tree, rhs: Tree) - extends TermTree - /** Array selection . only used during erasure */ case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) extends TermTree with RefTree @@ -155,8 +149,6 @@ trait Trees extends reflect.internal.Trees { self: Global => traverser.traverseTrees(ts) case DocDef(comment, definition) => traverser.traverse(definition) - case AssignOrNamedArg(lhs, rhs) => - traverser.traverse(lhs); traverser.traverse(rhs) case SelectFromArray(qualifier, selector, erasure) => traverser.traverse(qualifier) case ReferenceToBoxed(idt) => @@ -168,7 +160,6 @@ trait Trees extends reflect.internal.Trees { self: Global => trait TreeCopier extends super.TreeCopierOps { def DocDef(tree: Tree, comment: DocComment, definition: Tree): DocDef - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray def ReferenceToBoxed(tree: Tree, idt: Ident): ReferenceToBoxed def TypeTreeWithDeferredRefCheck(tree: Tree): TypeTreeWithDeferredRefCheck @@ -180,8 +171,6 @@ trait Trees extends reflect.internal.Trees { self: Global => class StrictTreeCopier extends super.StrictTreeCopier with TreeCopier { def DocDef(tree: Tree, comment: DocComment, definition: Tree) = new DocDef(comment, definition).copyAttrs(tree) - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = - new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) def ReferenceToBoxed(tree: Tree, idt: Ident) = @@ -197,11 +186,6 @@ trait Trees extends reflect.internal.Trees { self: Global => if (comment0 == comment) && (definition0 == definition) => t case _ => this.treeCopy.DocDef(tree, comment, definition) } - def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match { - case t @ AssignOrNamedArg(lhs0, rhs0) - if (lhs0 == lhs) && (rhs0 == rhs) => t - case _ => this.treeCopy.AssignOrNamedArg(tree, lhs, rhs) - } def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = tree match { case t @ SelectFromArray(qualifier0, selector0, _) if (qualifier0 == qualifier) && (selector0 == selector) => t @@ -232,8 +216,6 @@ trait Trees extends reflect.internal.Trees { self: Global => override protected def xtransform(transformer: super.Transformer, tree: Tree): Tree = tree match { case DocDef(comment, definition) => transformer.treeCopy.DocDef(tree, comment, transformer.transform(definition)) - case AssignOrNamedArg(lhs, rhs) => - transformer.treeCopy.AssignOrNamedArg(tree, transformer.transform(lhs), transformer.transform(rhs)) case SelectFromArray(qualifier, selector, erasure) => transformer.treeCopy.SelectFromArray( tree, transformer.transform(qualifier), selector, erasure) @@ -333,7 +315,6 @@ trait Trees extends reflect.internal.Trees { self: Global => case Parens(expr) (only used during parsing) case DocDef(comment, defn) => (eliminated by typer) - case AssignOrNamedArg(lhs, rhs) => (eliminated by typer) case TypeTreeWithDeferredRefCheck() => (created and eliminated by typer) case SelectFromArray(_, _, _) => (created and eliminated by erasure) diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 485a1f3a5c..e949cb3eb2 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -167,6 +167,7 @@ trait ScalaSettings extends AbsScalaSettings val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.") val Yreifydebug = BooleanSetting ("-Yreify-debug", "Trace reification.") + val Ymacrodebug = BooleanSetting ("-Ymacro-debug", "Trace macro-related activities: generation of synthetics, expansion, exceptions.") val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup") val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") . withPostSetHook(_ => interpreter.replProps.debug setValue true) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 48ec59234e..ed249796a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -49,7 +49,7 @@ trait Macros { self: Analyzer => * If `foo` is declared in an object, the second parameter list is () instead of (_this: _context.Tree). * If macro has no type arguments, the third parameter list is omitted (it's not empty, but omitted altogether). * - * To find out the desugared representation of your particular macro, compile it with -Ydebug. + * To find out the desugared representation of your particular macro, compile it with -Ymacro-debug. */ def macroMethDef(mdef: DefDef): Tree = { def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree) @@ -86,7 +86,7 @@ trait Macros { self: Analyzer => def addMacroMethods(templ: Template, namer: Namer): Unit = { for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) { - val trace = scala.tools.nsc.util.trace when settings.debug.value + val trace = scala.tools.nsc.util.trace when settings.Ymacrodebug.value val sym = namer.enterSyntheticSym(trace("macro def: ")(macroMethDef(ddef))) trace("added to "+namer.context.owner.enclClass+": ")(sym) } @@ -106,16 +106,43 @@ trait Macros { self: Analyzer => * not contain the macro implementation. */ def macroImpl(mac: Symbol): Option[(AnyRef, mirror.Symbol)] = { + val debug = settings.Ymacrodebug.value + val trace = scala.tools.nsc.util.trace when debug + trace("looking for macro implementation: ")(mac.fullNameString) + try { val mmeth = macroMeth(mac) + trace("found implementation at: ")(mmeth.fullNameString) + if (mmeth == NoSymbol) None else { val receiverClass: mirror.Symbol = mirror.symbolForName(mmeth.owner.fullName) + if (debug) { + println("receiverClass is: " + receiverClass.fullNameString) + + val jreceiverClass = mirror.classToJava(receiverClass) + val jreceiverSource = jreceiverClass.getProtectionDomain.getCodeSource + println("jreceiverClass is %s from %s".format(jreceiverClass, jreceiverSource)) + + val jreceiverClasspath = jreceiverClass.getClassLoader match { + case cl: java.net.URLClassLoader => "[" + (cl.getURLs mkString ",") + "]" + case _ => "" + } + println("jreceiverClassLoader is %s with classpath %s".format(jreceiverClass.getClassLoader, jreceiverClasspath)) + } + val receiverObj = receiverClass.companionModule + trace("receiverObj is: ")(receiverObj.fullNameString) + if (receiverObj == mirror.NoSymbol) None else { val receiver = mirror.companionInstance(receiverClass) val rmeth = receiverObj.info.member(mirror.newTermName(mmeth.name.toString)) + if (debug) { + println("rmeth is: " + rmeth.fullNameString) + println("jrmeth is: " + mirror.methodToJava(rmeth)) + } + if (rmeth == mirror.NoSymbol) None else { Some((receiver, rmeth)) @@ -133,16 +160,21 @@ trait Macros { self: Analyzer => * tree that calls this method instead of the macro. */ def macroExpand(tree: Tree, context: Context): Option[Any] = { + val trace = scala.tools.nsc.util.trace when settings.Ymacrodebug.value + trace("macroExpand: ")(tree) + val macroDef = tree.symbol macroImpl(macroDef) match { case Some((receiver, rmeth)) => val argss = List(global) :: macroArgs(tree) val paramss = macroMeth(macroDef).paramss + trace("paramss: ")(paramss) val rawArgss = for ((as, ps) <- argss zip paramss) yield { if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1) else as } val rawArgs: Seq[Any] = rawArgss.flatten + trace("rawArgs: ")(rawArgs) val savedInfolevel = nodePrinters.infolevel try { // @xeno.by: InfoLevel.Verbose examines and prints out infos of symbols @@ -156,16 +188,19 @@ trait Macros { self: Analyzer => } catch { case ex => val realex = ReflectionUtils.unwrapThrowable(ex) - val stacktrace = new java.io.StringWriter() - realex.printStackTrace(new java.io.PrintWriter(stacktrace)) - val msg = System.getProperty("line.separator") + stacktrace + val msg = if (settings.Ymacrodebug.value) { + val stacktrace = new java.io.StringWriter() + realex.printStackTrace(new java.io.PrintWriter(stacktrace)) + System.getProperty("line.separator") + stacktrace + } else { + realex.getMessage + } context.unit.error(tree.pos, "exception during macro expansion: " + msg) None } finally { nodePrinters.infolevel = savedInfolevel } case None => - val trace = scala.tools.nsc.util.trace when settings.debug.value def notFound() = { context.unit.error(tree.pos, "macro implementation not found: " + macroDef.name) None diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6f6edc62c7..ef69e1525e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1404,7 +1404,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def typedClassDef(cdef: ClassDef): Tree = { // attributes(cdef) val clazz = cdef.symbol - val typedMods = removeAnnotations(cdef.mods) + val typedMods = typedModifiers(cdef.mods) assert(clazz != NoSymbol, cdef) reenterTypeParams(cdef.tparams) val tparams1 = cdef.tparams mapConserve (typedTypeDef) @@ -1441,7 +1441,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { linkedClass.info.decl(nme.CONSTRUCTOR).alternatives foreach (_.initialize) val clazz = mdef.symbol.moduleClass - val typedMods = removeAnnotations(mdef.mods) + val typedMods = typedModifiers(mdef.mods) assert(clazz != NoSymbol, mdef) val impl1 = typerReportAnyContextErrors(context.make(mdef.impl, clazz, newScope)) { _.typedTemplate(mdef.impl, { @@ -1541,8 +1541,17 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { /** Remove definition annotations from modifiers (they have been saved * into the symbol's ``annotations'' in the type completer / namer) + * + * However reification does need annotation definitions to proceed. + * Unfortunately, AnnotationInfo doesn't provide enough info to reify it in general case. + * The biggest problem is with the "atp: Type" field, which cannot be reified in some situations + * that involve locally defined annotations. See more about that in Reifiers.scala. + * + * That's why the original tree gets saved into ``original'' field of AnnotationInfo (happens elsewhere). + * The field doesn't get pickled/unpickled and exists only during a single compilation run. + * This simultaneously allows us to reify annotations and to preserve backward compatibility. */ - def removeAnnotations(mods: Modifiers): Modifiers = + def typedModifiers(mods: Modifiers): Modifiers = mods.copy(annotations = Nil) setPositions mods.positions /** @@ -1553,7 +1562,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // attributes(vdef) val sym = vdef.symbol.initialize val typer1 = constrTyperIf(sym.isParameter && sym.owner.isConstructor) - val typedMods = removeAnnotations(vdef.mods) + val typedMods = typedModifiers(vdef.mods) // complete lazy annotations val annots = sym.annotations @@ -1764,7 +1773,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { var tpt1 = checkNoEscaping.privates(meth, typedType(ddef.tpt)) checkNonCyclic(ddef, tpt1) ddef.tpt.setType(tpt1.tpe) - val typedMods = removeAnnotations(ddef.mods) + val typedMods = typedModifiers(ddef.mods) var rhs1 = if (ddef.name == nme.CONSTRUCTOR && !ddef.symbol.hasStaticFlag) { // need this to make it possible to generate static ctors if (!meth.isPrimaryConstructor && @@ -1813,7 +1822,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { tdef.symbol.initialize reenterTypeParams(tdef.tparams) val tparams1 = tdef.tparams mapConserve typedTypeDef - val typedMods = removeAnnotations(tdef.mods) + val typedMods = typedModifiers(tdef.mods) // complete lazy annotations val annots = tdef.symbol.annotations @@ -2770,7 +2779,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } if (hasError) annotationError - else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setPos(ann.pos) + else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setOriginal(ann).setPos(ann.pos) } } else if (requireJava) { reportAnnotationError(NestedAnnotationError(ann, annType)) @@ -2810,7 +2819,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def annInfo(t: Tree): AnnotationInfo = t match { case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => - AnnotationInfo(annType, args, List()).setPos(t.pos) + AnnotationInfo(annType, args, List()).setOriginal(ann).setPos(t.pos) case Block(stats, expr) => context.warning(t.pos, "Usage of named or default arguments transformed this annotation\n"+ diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index 32940cbcd6..2c960392ec 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -439,6 +439,12 @@ trait Trees { self: Universe => case class Assign(lhs: Tree, rhs: Tree) extends TermTree + /** Either an assignment or a named argument. Only appears in argument lists, + * eliminated by typecheck (doTypedApply) + */ + case class AssignOrNamedArg(lhs: Tree, rhs: Tree) + extends TermTree + /** Conditional expression */ case class If(cond: Tree, thenp: Tree, elsep: Tree) extends TermTree @@ -716,6 +722,8 @@ trait Trees { self: Universe => } case Assign(lhs, rhs) => traverse(lhs); traverse(rhs) + case AssignOrNamedArg(lhs, rhs) => + traverse(lhs); traverse(rhs) case If(cond, thenp, elsep) => traverse(cond); traverse(thenp); traverse(elsep) case Match(selector, cases) => @@ -814,6 +822,7 @@ trait Trees { self: Universe => def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree): AssignOrNamedArg def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match def Return(tree: Tree, expr: Tree): Return @@ -876,6 +885,8 @@ trait Trees { self: Universe => new Function(vparams, body).copyAttrs(tree) def Assign(tree: Tree, lhs: Tree, rhs: Tree) = new Assign(lhs, rhs).copyAttrs(tree) + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = + new AssignOrNamedArg(lhs, rhs).copyAttrs(tree) def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = new If(cond, thenp, elsep).copyAttrs(tree) def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = @@ -1021,6 +1032,11 @@ trait Trees { self: Universe => if (lhs0 == lhs) && (rhs0 == rhs) => t case _ => treeCopy.Assign(tree, lhs, rhs) } + def AssignOrNamedArg(tree: Tree, lhs: Tree, rhs: Tree) = tree match { + case t @ AssignOrNamedArg(lhs0, rhs0) + if (lhs0 == lhs) && (rhs0 == rhs) => t + case _ => treeCopy.AssignOrNamedArg(tree, lhs, rhs) + } def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match { case t @ If(cond0, thenp0, elsep0) if (cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep) => t @@ -1205,6 +1221,8 @@ trait Trees { self: Universe => } case Assign(lhs, rhs) => treeCopy.Assign(tree, transform(lhs), transform(rhs)) + case AssignOrNamedArg(lhs, rhs) => + treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs)) case If(cond, thenp, elsep) => treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep)) case Match(selector, cases) => @@ -1372,6 +1390,8 @@ trait Trees { self: Universe => // vparams => body where vparams:List[ValDef] case Assign(lhs, rhs) => // lhs = rhs + case AssignOrNamedArg(lhs, rhs) => (eliminated by typer, resurrected by reifier) + // @annotation(lhs = rhs) case If(cond, thenp, elsep) => // if (cond) thenp else elsep case Match(selector, cases) => diff --git a/test/files/neg/reify_ann2a.check b/test/files/neg/reify_ann2a.check new file mode 100644 index 0000000000..2afe37e1d8 --- /dev/null +++ b/test/files/neg/reify_ann2a.check @@ -0,0 +1,4 @@ +reify_ann2a.scala:9: error: exception during macro expansion: implementation restriction: cannot reify annotation @ann(immutable.this.List.apply[String]("1a")) which involves a symbol declared inside the block being reified + val tree = scala.reflect.Code.lift{ + ^ +one error found diff --git a/test/files/neg/reify_ann2a.scala b/test/files/neg/reify_ann2a.scala new file mode 100644 index 0000000000..071919eb76 --- /dev/null +++ b/test/files/neg/reify_ann2a.scala @@ -0,0 +1,30 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + class ann(bar: List[String]) extends StaticAnnotation + + @ann(bar=List("1a")) @ann(bar=List("1b")) class C[@ann(bar=List("2a")) @ann(bar=List("2b")) T](@ann(bar=List("3a")) @ann(bar=List("3b")) x: T @ann(bar=List("4a")) @ann(bar=List("4b"))) { + @ann(bar=List("5a")) @ann(bar=List("5b")) def f(x: Int @ann(bar=List("6a")) @ann(bar=List("6b"))) = { + @ann(bar=List("7a")) @ann(bar=List("7b")) val r = (x + 3): @ann(bar=List("8a")) @ann(bar=List("8b")) + val s = 4: Int @ann(bar=List("9a")) @ann(bar=List("9b")) + r + s + } + } + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/files/neg/reify_ann2b.check b/test/files/neg/reify_ann2b.check new file mode 100644 index 0000000000..ceb70689f1 --- /dev/null +++ b/test/files/neg/reify_ann2b.check @@ -0,0 +1,7 @@ +reify_ann2b.scala:10: error: inner classes cannot be classfile annotations + class ann(bar: String) extends ClassfileAnnotation + ^ +reify_ann2b.scala:9: error: exception during macro expansion: implementation restriction: cannot reify annotation @ann(bar = "1a") which involves a symbol declared inside the block being reified + val tree = scala.reflect.Code.lift{ + ^ +two errors found diff --git a/test/files/neg/reify_ann2b.scala b/test/files/neg/reify_ann2b.scala new file mode 100644 index 0000000000..74273ad6ec --- /dev/null +++ b/test/files/neg/reify_ann2b.scala @@ -0,0 +1,30 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + class ann(bar: String) extends ClassfileAnnotation + + @ann(bar="1a") @ann(bar="1b") class C[@ann(bar="2a") @ann(bar="2b") T](@ann(bar="3a") @ann(bar="3b") x: T @ann(bar="4a") @ann(bar="4b")) { + @ann(bar="5a") @ann(bar="5b") def f(x: Int @ann(bar="6a") @ann(bar="6b")) = { + @ann(bar="7a") @ann(bar="7b") val r = (x + 3): @ann(bar="8a") @ann(bar="8b") + val s = 4: Int @ann(bar="9a") @ann(bar="9b") + r + s + } + } + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/files/run/reify_ann1a.check b/test/files/run/reify_ann1a.check new file mode 100644 index 0000000000..2822238706 --- /dev/null +++ b/test/files/run/reify_ann1a.check @@ -0,0 +1,30 @@ +{ + @new ann(immutable.this.List.apply[String]("1a")) @new ann(immutable.this.List.apply[String]("1b")) class C[@new ann(immutable.this.List.apply[String]("2a")) @new ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends Object with ScalaObject { + @new ann(immutable.this.List.apply[String]("3a")) @new ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4a")) @ann(immutable.this.List.apply[String]("4b")) = _; + def (@new ann(immutable.this.List.apply[String]("3a")) @new ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4a")) @ann(immutable.this.List.apply[String]("4b"))) = { + super.(); + () + }; + @new ann(immutable.this.List.apply[String]("5a")) @new ann(immutable.this.List.apply[String]("5b")) def f(x: Int @ann(immutable.this.List.apply[String]("6b")) @ann(immutable.this.List.apply[String]("6a"))): Int = { + @new ann(immutable.this.List.apply[String]("7a")) @new ann(immutable.this.List.apply[String]("7b")) val r: Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a")) = ((x.$plus(3): Int @ann(immutable.this.List.apply[String]("8a"))): Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a"))); + val s: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a")) = (4: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a"))); + r.$plus(s) + } + }; + () +} +{ + @ann(immutable.this.List.apply[String]("1a")) @ann(immutable.this.List.apply[String]("1b")) class C[@ann(immutable.this.List.apply[String]("2a")) @ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends Object with ScalaObject { + @ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a")) = _; + def (@ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a"))): C[T] = { + C.super.(); + () + }; + @ann(immutable.this.List.apply[String]("5a")) @ann(immutable.this.List.apply[String]("5b")) def f(x: Int @ann(immutable.this.List.apply[String]("6b")) @ann(immutable.this.List.apply[String]("6a"))): Int = { + @ann(immutable.this.List.apply[String]("7a")) @ann(immutable.this.List.apply[String]("7b")) val r: Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a")) = ((x.+(3): Int @ann(immutable.this.List.apply[String]("8a"))): Int @ann(immutable.this.List.apply[String]("8b")) @ann(immutable.this.List.apply[String]("8a"))); + val s: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a")) = (4: Int @ann(immutable.this.List.apply[String]("9b")) @ann(immutable.this.List.apply[String]("9a"))); + r.+(s) + } + }; + () +} diff --git a/test/files/run/reify_ann1a.scala b/test/files/run/reify_ann1a.scala new file mode 100644 index 0000000000..933ea21b20 --- /dev/null +++ b/test/files/run/reify_ann1a.scala @@ -0,0 +1,30 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +class ann(bar: List[String]) extends StaticAnnotation + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + @ann(bar=List("1a")) @ann(bar=List("1b")) class C[@ann(bar=List("2a")) @ann(bar=List("2b")) T](@ann(bar=List("3a")) @ann(bar=List("3b")) x: T @ann(bar=List("4a")) @ann(bar=List("4b"))) { + @ann(bar=List("5a")) @ann(bar=List("5b")) def f(x: Int @ann(bar=List("6a")) @ann(bar=List("6b"))) = { + @ann(bar=List("7a")) @ann(bar=List("7b")) val r = (x + 3): @ann(bar=List("8a")) @ann(bar=List("8b")) + val s = 4: Int @ann(bar=List("9a")) @ann(bar=List("9b")) + r + s + } + } + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/files/run/reify_ann1b.check b/test/files/run/reify_ann1b.check new file mode 100644 index 0000000000..e240e1e0ce --- /dev/null +++ b/test/files/run/reify_ann1b.check @@ -0,0 +1,30 @@ +{ + @new ann(bar = "1a") @new ann(bar = "1b") class C[@new ann(bar = "2a") @new ann(bar = "2b") T>: Nothing <: Any] extends Object with ScalaObject { + @new ann(bar = "3a") @new ann(bar = "3b") private[this] val x: T @ann(bar = "4a") @ann(bar = "4b") = _; + def (@new ann(bar = "3a") @new ann(bar = "3b") x: T @ann(bar = "4a") @ann(bar = "4b")) = { + super.(); + () + }; + @new ann(bar = "5a") @new ann(bar = "5b") def f(x: Int @ann(bar = "6b") @ann(bar = "6a")): Int = { + @new ann(bar = "7a") @new ann(bar = "7b") val r: Int @ann(bar = "8b") @ann(bar = "8a") = ((x.$plus(3): Int @ann(bar = "8a")): Int @ann(bar = "8b") @ann(bar = "8a")); + val s: Int @ann(bar = "9b") @ann(bar = "9a") = (4: Int @ann(bar = "9b") @ann(bar = "9a")); + r.$plus(s) + } + }; + () +} +{ + @ann(bar = "1a") @ann(bar = "1b") class C[@ann(bar = "2a") @ann(bar = "2b") T>: Nothing <: Any] extends Object with ScalaObject { + @ann(bar = "3a") @ann(bar = "3b") private[this] val x: T @ann(bar = "4b") @ann(bar = "4a") = _; + def (@ann(bar = "3a") @ann(bar = "3b") x: T @ann(bar = "4b") @ann(bar = "4a")): C[T] = { + C.super.(); + () + }; + @ann(bar = "5a") @ann(bar = "5b") def f(x: Int @ann(bar = "6b") @ann(bar = "6a")): Int = { + @ann(bar = "7a") @ann(bar = "7b") val r: Int @ann(bar = "8b") @ann(bar = "8a") = ((x.+(3): Int @ann(bar = "8a")): Int @ann(bar = "8b") @ann(bar = "8a")); + val s: Int @ann(bar = "9b") @ann(bar = "9a") = (4: Int @ann(bar = "9b") @ann(bar = "9a")); + r.+(s) + } + }; + () +} diff --git a/test/files/run/reify_ann1b.scala b/test/files/run/reify_ann1b.scala new file mode 100644 index 0000000000..53dfe08086 --- /dev/null +++ b/test/files/run/reify_ann1b.scala @@ -0,0 +1,30 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +class ann(bar: String) extends ClassfileAnnotation + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + @ann(bar="1a") @ann(bar="1b") class C[@ann(bar="2a") @ann(bar="2b") T](@ann(bar="3a") @ann(bar="3b") x: T @ann(bar="4a") @ann(bar="4b")) { + @ann(bar="5a") @ann(bar="5b") def f(x: Int @ann(bar="6a") @ann(bar="6b")) = { + @ann(bar="7a") @ann(bar="7b") val r = (x + 3): @ann(bar="8a") @ann(bar="8b") + val s = 4: Int @ann(bar="9a") @ann(bar="9b") + r + s + } + } + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/files/run/reify_classfileann_a.check b/test/files/run/reify_classfileann_a.check new file mode 100644 index 0000000000..1773263a94 --- /dev/null +++ b/test/files/run/reify_classfileann_a.check @@ -0,0 +1,18 @@ +{ + @new ann(bar = "1", quux = Array("2", "3"), baz = new ann(bar = "4")) class C extends Object with ScalaObject { + def () = { + super.(); + () + } + }; + () +} +{ + @ann(bar = "1", quux = ["2", "3"], baz = ann(bar = "4")) class C extends Object with ScalaObject { + def (): C = { + C.super.(); + () + } + }; + () +} diff --git a/test/files/run/reify_classfileann_a.scala b/test/files/run/reify_classfileann_a.scala new file mode 100644 index 0000000000..6bf4750bbc --- /dev/null +++ b/test/files/run/reify_classfileann_a.scala @@ -0,0 +1,24 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +class ann(bar: String, quux: Array[String] = Array(), baz: ann = null) extends ClassfileAnnotation + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + @ann(bar="1", quux=Array("2", "3"), baz = new ann(bar = "4")) class C + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/files/run/t5224.check b/test/files/run/t5224.check new file mode 100644 index 0000000000..5bead91b36 --- /dev/null +++ b/test/files/run/t5224.check @@ -0,0 +1,9 @@ +{ + @new Foo(bar = "qwe") class C extends Object with ScalaObject { + def () = { + super.(); + () + } + }; + () +} diff --git a/test/files/run/t5224.scala b/test/files/run/t5224.scala new file mode 100644 index 0000000000..2226a69a05 --- /dev/null +++ b/test/files/run/t5224.scala @@ -0,0 +1,9 @@ +import scala.reflect._ +import scala.reflect.api._ + +class Foo(bar: String) extends ClassfileAnnotation + +object Test extends App { + val tree = scala.reflect.Code.lift{@Foo(bar = "qwe") class C}.tree + println(tree.toString) +} \ No newline at end of file diff --git a/test/files/run/t5225_1.check b/test/files/run/t5225_1.check new file mode 100644 index 0000000000..719da572c7 --- /dev/null +++ b/test/files/run/t5225_1.check @@ -0,0 +1,4 @@ +{ + @new transient() @new volatile() var x: Int = 2; + () +} diff --git a/test/files/run/t5225_1.scala b/test/files/run/t5225_1.scala new file mode 100644 index 0000000000..a655b7dd71 --- /dev/null +++ b/test/files/run/t5225_1.scala @@ -0,0 +1,7 @@ +import scala.reflect._ +import scala.reflect.api._ + +object Test extends App { + val tree = scala.reflect.Code.lift{@transient @volatile var x = 2}.tree + println(tree.toString) +} \ No newline at end of file diff --git a/test/files/run/t5225_2.check b/test/files/run/t5225_2.check new file mode 100644 index 0000000000..c4f6b4761e --- /dev/null +++ b/test/files/run/t5225_2.check @@ -0,0 +1,4 @@ +{ + def foo(@new cloneable() x: Int): String = ""; + () +} diff --git a/test/files/run/t5225_2.scala b/test/files/run/t5225_2.scala new file mode 100644 index 0000000000..65ea9b2f73 --- /dev/null +++ b/test/files/run/t5225_2.scala @@ -0,0 +1,7 @@ +import scala.reflect._ +import scala.reflect.api._ + +object Test extends App { + val tree = scala.reflect.Code.lift{def foo(@cloneable x: Int) = ""}.tree + println(tree.toString) +} \ No newline at end of file diff --git a/test/files/run/t5419.check b/test/files/run/t5419.check new file mode 100644 index 0000000000..7e6d739354 --- /dev/null +++ b/test/files/run/t5419.check @@ -0,0 +1 @@ +(5: Int(5) @Foo) diff --git a/test/files/run/t5419.scala b/test/files/run/t5419.scala new file mode 100644 index 0000000000..695786e5c4 --- /dev/null +++ b/test/files/run/t5419.scala @@ -0,0 +1,9 @@ +import scala.reflect._ +import scala.reflect.api._ + +class Foo extends StaticAnnotation + +object Test extends App { + val tree = scala.reflect.Code.lift{5: @Foo}.tree + println(tree.toString) +} \ No newline at end of file diff --git a/test/pending/run/reify_classfileann_b.check b/test/pending/run/reify_classfileann_b.check new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/pending/run/reify_classfileann_b.scala b/test/pending/run/reify_classfileann_b.scala new file mode 100644 index 0000000000..b76dd8fc9f --- /dev/null +++ b/test/pending/run/reify_classfileann_b.scala @@ -0,0 +1,28 @@ +import scala.reflect._ +import scala.reflect.api._ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +class ann(bar: String, quux: Array[String] = Array(), baz: ann = null) extends ClassfileAnnotation + +object Test extends App { + // test 1: reify + val tree = scala.reflect.Code.lift{ + class C { + def x: Int = { + 2: @ann(bar="1", quux=Array("2", "3"), baz = new ann(bar = "4")) + } + } + }.tree + println(tree.toString) + + // test 2: import and typecheck + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + val ttree = toolbox.typeCheck(tree) + println(ttree.toString) + + // test 3: import and compile + toolbox.runExpr(ttree) +} \ No newline at end of file diff --git a/test/pending/run/t5224.check b/test/pending/run/t5224.check deleted file mode 100644 index 2b920773c0..0000000000 --- a/test/pending/run/t5224.check +++ /dev/null @@ -1,9 +0,0 @@ -{ - @serializable class C extends Object with ScalaObject { - def () = { - super.(); - () - } - }; - () -} \ No newline at end of file diff --git a/test/pending/run/t5224.scala b/test/pending/run/t5224.scala deleted file mode 100644 index 865ce4bfe9..0000000000 --- a/test/pending/run/t5224.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.reflect._ -import scala.reflect.api._ - -object Test extends App { - println(scala.reflect.Code.lift{ - @serializable class C - }.tree.toString) -} \ No newline at end of file diff --git a/test/pending/run/t5225_1.check b/test/pending/run/t5225_1.check deleted file mode 100644 index b29cd9c365..0000000000 --- a/test/pending/run/t5225_1.check +++ /dev/null @@ -1,4 +0,0 @@ -{ - @transient @volatile var x: Int = 2; - () -} \ No newline at end of file diff --git a/test/pending/run/t5225_1.scala b/test/pending/run/t5225_1.scala deleted file mode 100644 index 454502e810..0000000000 --- a/test/pending/run/t5225_1.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.reflect._ -import scala.reflect.api._ - -object Test extends App { - println(scala.reflect.Code.lift{ - @transient @volatile var x = 2 - }.tree.toString) -} \ No newline at end of file diff --git a/test/pending/run/t5225_2.check b/test/pending/run/t5225_2.check deleted file mode 100644 index 88972fd27f..0000000000 --- a/test/pending/run/t5225_2.check +++ /dev/null @@ -1,4 +0,0 @@ -{ - def foo(@cloneable x: Int): String = ""; - () -} diff --git a/test/pending/run/t5225_2.scala b/test/pending/run/t5225_2.scala deleted file mode 100644 index 82bad0f353..0000000000 --- a/test/pending/run/t5225_2.scala +++ /dev/null @@ -1,8 +0,0 @@ -import scala.reflect._ -import scala.reflect.api._ - -object Test extends App { - println(scala.reflect.Code.lift{ - def foo(@cloneable x: Int) = "" - }.tree.toString) -} \ No newline at end of file -- cgit v1.2.3 From 2b731911e97a281e324060099631e2374b2144ec Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 13 Feb 2012 23:09:39 -0800 Subject: Fix for SI-5452. Why is calling the error function not enough to register the error, why does "setError(tree)" have to be called as well? That was the cause of this particular stackoverflow. In ContextErrors I see lots of methods which call setError and lots more which do not, and frankly it's all pretty terrifying. There is zero documentation attached to setError. Maybe there's an explanation somewhere I'm not seeing. Review by @hubertp. --- .../tools/nsc/typechecker/ContextErrors.scala | 4 ++- test/files/neg/t5452.check | 6 +++++ test/files/neg/t5452.scala | 29 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t5452.check create mode 100644 test/files/neg/t5452.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 6ee09d064f..466b5125a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -714,9 +714,11 @@ trait ContextErrors { setError(tree) } - def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + setError(tree) + } def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, argtpes: List[Type], pt: Type) = { diff --git a/test/files/neg/t5452.check b/test/files/neg/t5452.check new file mode 100644 index 0000000000..baf544499b --- /dev/null +++ b/test/files/neg/t5452.check @@ -0,0 +1,6 @@ +t5452.scala:28: error: overloaded method value apply with alternatives: + + cannot be applied to (Queryable[CoffeesTable]) + Queryable[CoffeesTable]( q.treeFilter(null) ) + ^ +one error found diff --git a/test/files/neg/t5452.scala b/test/files/neg/t5452.scala new file mode 100644 index 0000000000..1032db7a4b --- /dev/null +++ b/test/files/neg/t5452.scala @@ -0,0 +1,29 @@ +// /scala/trac/5452/a.scala +// Mon Feb 13 22:52:36 PST 2012 + +// import scala.reflect.mirror._ + +trait Tree + +object Bip { + def ??? = sys.error("") +} +import Bip._ + +case class Queryable[T]() { + def treeFilter( t:Tree ) : Queryable[T] = ??? +} + +object Queryable { + def apply[T:Manifest] = ??? + def apply[T:Manifest]( t:Tree ) = ??? +} + +trait CoffeesTable{ + def sales : Int +} + +object Test extends App{ + val q = new Queryable[CoffeesTable] + Queryable[CoffeesTable]( q.treeFilter(null) ) +} -- cgit v1.2.3 From a725bf982c06e16c5d533ea6b2227b726db4f7e4 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 14 Feb 2012 06:16:09 -0800 Subject: Make fix for SI-5452 not break other things. If this looks hacky, that's because it is. --- src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 4 +--- src/compiler/scala/tools/nsc/typechecker/Infer.scala | 7 ++++++- test/files/neg/t5452.check | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 466b5125a8..6ee09d064f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -714,11 +714,9 @@ trait ContextErrors { setError(tree) } - def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) - setError(tree) - } def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, argtpes: List[Type], pt: Type) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b97fbebec2..acf905d974 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1466,7 +1466,9 @@ trait Infer { argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 + var secondTry = true tryTwice { + secondTry = !secondTry debuglog("infer method alt "+ tree.symbol +" with alternatives "+ (alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt) @@ -1488,8 +1490,11 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) + if (pt == WildcardType) { NoBestMethodAlternativeError(tree, argtpes, pt) + if (secondTry) + setError(tree) + } else inferMethodAlternative(tree, undetparams, argtpes, WildcardType) } else if (!competing.isEmpty) { diff --git a/test/files/neg/t5452.check b/test/files/neg/t5452.check index baf544499b..2f35a45509 100644 --- a/test/files/neg/t5452.check +++ b/test/files/neg/t5452.check @@ -1,5 +1,7 @@ t5452.scala:28: error: overloaded method value apply with alternatives: - + ()Queryable[CoffeesTable] + (t: Tree)(implicit evidence$2: Manifest[CoffeesTable])Nothing + (implicit evidence$1: Manifest[CoffeesTable])Nothing cannot be applied to (Queryable[CoffeesTable]) Queryable[CoffeesTable]( q.treeFilter(null) ) ^ -- cgit v1.2.3 From 97ec16850b152e6e03aba351cc918c66583362f3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 14 Feb 2012 21:59:43 +0100 Subject: Disables typechecking that precedes reflective compilation Previously toolboxes used to typecheck their inputs before compiling. Actually, the initial demo by Martin first typechecked the reified tree, then ran it, which typechecked it again, and only then launched the reflective compiler. However, as observed in https://issues.scala-lang.org/browse/SI-5464 current implementation of typechecking is not always idempotent. That's why we cannot allow inputs of toolboxes to be typechecked, at least not until the aforementioned issue is closed. This is not only a convention but also a check inside compileExpr. --- .../scala/reflect/internal/Importers.scala | 2 +- src/compiler/scala/reflect/runtime/ToolBoxes.scala | 40 ++++---- test/files/neg/reify_ann2a.scala | 2 +- test/files/neg/reify_ann2b.scala | 2 +- test/files/run/reify_ann1a.scala | 2 +- test/files/run/reify_ann1b.scala | 2 +- test/files/run/reify_anonymous.scala | 3 +- test/files/run/reify_classfileann_a.scala | 2 +- test/files/run/reify_closure1.scala | 3 +- test/files/run/reify_closure2a.scala | 3 +- test/files/run/reify_closure3a.scala | 3 +- test/files/run/reify_closure4a.scala | 3 +- test/files/run/reify_closure5a.scala | 3 +- test/files/run/reify_closure6.scala | 3 +- test/files/run/reify_closure7.scala | 3 +- test/files/run/reify_closure8a.scala | 3 +- test/files/run/reify_closures10.scala | 3 +- test/files/run/reify_complex.scala | 3 +- test/files/run/reify_extendbuiltins.scala | 3 +- test/files/run/reify_for1.scala | 3 +- test/files/run/reify_fors.check | 5 + test/files/run/reify_fors.scala | 106 ++++++++++++++++++++ test/files/run/reify_generic.scala | 3 +- test/files/run/reify_generic2.scala | 3 +- test/files/run/reify_getter.scala | 3 +- test/files/run/reify_implicits.scala | 3 +- test/files/run/reify_inheritance.scala | 3 +- test/files/run/reify_inner1.scala | 3 +- test/files/run/reify_inner2.scala | 3 +- test/files/run/reify_inner3.scala | 3 +- test/files/run/reify_inner4.scala | 3 +- test/files/run/reify_maps.check | 4 + test/files/run/reify_maps.scala | 25 +++++ test/files/run/reify_printf.scala | 3 +- test/files/run/reify_sort.scala | 3 +- test/files/run/reify_sort1.scala | 3 +- test/files/run/reify_this.scala | 3 +- test/files/run/reify_timeofday.check | 1 + test/files/run/reify_timeofday.scala | 47 +++++++++ test/files/run/reify_varargs.scala | 3 +- test/files/run/t5229_1.scala | 3 +- test/files/run/t5229_2.check | 2 +- test/files/run/t5229_2.scala | 3 +- test/files/run/t5230.check | 2 +- test/files/run/t5230.scala | 3 +- test/files/run/t5258a.scala | 3 +- test/files/run/t5266_1.check | 2 +- test/files/run/t5266_1.scala | 3 +- test/files/run/t5266_2.check | 2 +- test/files/run/t5266_2.scala | 3 +- test/files/run/t5269.scala | 3 +- test/files/run/t5270.scala | 3 +- test/files/run/t5271_1.check | 11 +++ test/files/run/t5271_1.scala | 3 +- test/files/run/t5271_2.check | 13 ++- test/files/run/t5271_2.scala | 3 +- test/files/run/t5271_3.check | 20 +++- test/files/run/t5271_3.scala | 3 +- test/files/run/t5271_4.scala | 3 +- test/files/run/t5272_1.scala | 3 +- test/files/run/t5272_2.scala | 3 +- test/files/run/t5273_1.scala | 3 +- test/files/run/t5273_2a.scala | 3 +- test/files/run/t5273_2b.scala | 3 +- test/files/run/t5274_1.scala | 3 +- test/files/run/t5274_2.scala | 3 +- test/files/run/t5275.scala | 3 +- test/files/run/t5276_1a.scala | 3 +- test/files/run/t5276_1b.scala | 5 +- test/files/run/t5276_2a.scala | 3 +- test/files/run/t5276_2b.scala | 3 +- test/files/run/t5277_1.scala | 3 +- test/files/run/t5277_2.scala | 3 +- test/files/run/t5279.scala | 3 +- test/files/run/t5334_1.check | 1 - test/files/run/t5334_1.scala | 4 +- test/files/run/t5334_2.check | 1 - test/files/run/t5334_2.scala | 4 +- test/files/run/t5335.scala | 3 +- test/pending/run/reify_addressbook.scala | 3 +- test/pending/run/reify_brainf_ck.scala | 3 +- test/pending/run/reify_callccinterpreter.scala | 3 +- test/pending/run/reify_classfileann_b.scala | 8 +- test/pending/run/reify_closure2b.scala | 3 +- test/pending/run/reify_closure3b.scala | 3 +- test/pending/run/reify_closure4b.scala | 3 +- test/pending/run/reify_closure5b.scala | 3 +- test/pending/run/reify_closure8b.scala | 3 +- test/pending/run/reify_closure9a.scala | 3 +- test/pending/run/reify_closure9b.scala | 3 +- test/pending/run/reify_closures11.scala | 3 +- test/pending/run/reify_csv.scala | 3 +- test/pending/run/reify_fors.check | 5 - test/pending/run/reify_fors.scala | 107 --------------------- test/pending/run/reify_gadts.scala | 3 +- test/pending/run/reify_lazyevaluation.scala | 3 +- test/pending/run/reify_maps.check | 4 - test/pending/run/reify_maps.scala | 26 ----- test/pending/run/reify_properties.scala | 3 +- test/pending/run/reify_simpleinterpreter.scala | 3 +- test/pending/run/reify_timeofday.check | 1 - test/pending/run/reify_timeofday.scala | 48 --------- test/pending/run/t5258b.scala | 3 +- test/pending/run/t5258c.scala | 3 +- test/pending/run/t5271_1.check | 0 test/pending/run/t5271_1.scala | 13 +++ test/pending/run/t5271_2.check | 1 + test/pending/run/t5271_2.scala | 15 +++ test/pending/run/t5271_3.check | 1 + test/pending/run/t5271_3.scala | 16 +++ test/pending/run/t5418.scala | 3 +- 111 files changed, 388 insertions(+), 383 deletions(-) create mode 100644 test/files/run/reify_fors.check create mode 100644 test/files/run/reify_fors.scala create mode 100644 test/files/run/reify_maps.check create mode 100644 test/files/run/reify_maps.scala create mode 100644 test/files/run/reify_timeofday.check create mode 100644 test/files/run/reify_timeofday.scala delete mode 100644 test/pending/run/reify_fors.check delete mode 100644 test/pending/run/reify_fors.scala delete mode 100644 test/pending/run/reify_maps.check delete mode 100644 test/pending/run/reify_maps.scala delete mode 100644 test/pending/run/reify_timeofday.check delete mode 100644 test/pending/run/reify_timeofday.scala create mode 100644 test/pending/run/t5271_1.check create mode 100644 test/pending/run/t5271_1.scala create mode 100644 test/pending/run/t5271_2.check create mode 100644 test/pending/run/t5271_2.scala create mode 100644 test/pending/run/t5271_3.check create mode 100644 test/pending/run/t5271_3.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index c232e3b7c1..1ae4f755ed 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -286,7 +286,7 @@ trait Importers { self: SymbolTable => new Modifiers(mods.flags, importName(mods.privateWithin), mods.annotations map importTree) def importImportSelector(sel: from.ImportSelector): ImportSelector = - new ImportSelector(importName(sel.name), sel.namePos, importName(sel.rename), sel.renamePos) + new ImportSelector(importName(sel.name), sel.namePos, if (sel.rename != null) importName(sel.rename) else null, sel.renamePos) def importTree(tree: from.Tree): Tree = { val mytree = tree match { diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala index 880c68eaa0..f52662ce6f 100644 --- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala +++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala @@ -64,7 +64,7 @@ trait ToolBoxes extends { self: Universe => obj setInfo obj.moduleClass.tpe val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) def makeParam(fv: Symbol) = meth.newValueParameter(fv.name.toTermName) setInfo fv.tpe - meth setInfo MethodType(fvs map makeParam, expr.tpe) + meth setInfo MethodType(fvs map makeParam, AnyClass.tpe) minfo.decls enter meth trace("wrapping ")(defOwner(expr) -> meth) val methdef = DefDef(meth, expr changeOwner (defOwner(expr) -> meth)) @@ -94,6 +94,20 @@ trait ToolBoxes extends { self: Universe => } def compileExpr(expr: Tree, fvs: List[Symbol]): String = { + // Previously toolboxes used to typecheck their inputs before compiling. + // Actually, the initial demo by Martin first typechecked the reified tree, + // then ran it, which typechecked it again, and only then launched the + // reflective compiler. + // + // However, as observed in https://issues.scala-lang.org/browse/SI-5464 + // current implementation typechecking is not always idempotent. + // That's why we cannot allow inputs of toolboxes to be typechecked, + // at least not until the aforementioned issue is closed. + val typed = expr filter (t => t.tpe != null && t.tpe != NoType && !t.isInstanceOf[TypeTree]) + if (!typed.isEmpty) { + throw new Error("cannot compile trees that are already typed") + } + val mdef = wrapInObject(expr, fvs) val pdef = wrapInPackage(mdef) val unit = wrapInCompilationUnit(pdef) @@ -106,7 +120,6 @@ trait ToolBoxes extends { self: Universe => jclazz.getDeclaredMethods.find(_.getName == name).get def runExpr(expr: Tree): Any = { - val etpe = expr.tpe val fvs = (expr filter isFree map (_.symbol)).distinct reporter.reset() @@ -181,19 +194,13 @@ trait ToolBoxes extends { self: Universe => lazy val classLoader = new AbstractFileClassLoader(virtualDirectory, defaultReflectiveClassLoader) - private def importAndTypeCheck(tree: rm.Tree, expectedType: rm.Type): compiler.Tree = { + def typeCheck(tree: rm.Tree, expectedType: rm.Type): rm.Tree = { + if (compiler.settings.verbose.value) println("typing "+tree+", pt = "+expectedType) val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree]) val pt: compiler.Type = importer.importType(expectedType.asInstanceOf[Type]) -// val typer = compiler.typer.atOwner(ctree, if (owner.isModule) cowner.moduleClass else cowner) val ttree: compiler.Tree = compiler.typedTopLevelExpr(ctree, pt) - ttree - } - - def typeCheck(tree: rm.Tree, expectedType: rm.Type): rm.Tree = { - if (compiler.settings.verbose.value) println("typing "+tree+", pt = "+expectedType) - val ttree = importAndTypeCheck(tree, expectedType) - val ettree = exporter.importTree(ttree).asInstanceOf[rm.Tree] - ettree + val rmttree = exporter.importTree(ttree).asInstanceOf[rm.Tree] + rmttree } def typeCheck(tree: rm.Tree): rm.Tree = @@ -202,11 +209,10 @@ trait ToolBoxes extends { self: Universe => def showAttributed(tree: rm.Tree, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = compiler.showAttributed(importer.importTree(tree.asInstanceOf[Tree]), printTypes, printIds, printKinds) - def runExpr(tree: rm.Tree, expectedType: rm.Type): Any = { - val ttree = importAndTypeCheck(tree, expectedType) - compiler.runExpr(ttree) + def runExpr(tree: rm.Tree): Any = { + if (compiler.settings.verbose.value) println("running "+tree) + val ctree: compiler.Tree = importer.importTree(tree.asInstanceOf[Tree]) + compiler.runExpr(ctree) } - - def runExpr(tree: rm.Tree): Any = runExpr(tree, WildcardType.asInstanceOf[rm.Type]) } } diff --git a/test/files/neg/reify_ann2a.scala b/test/files/neg/reify_ann2a.scala index 071919eb76..8de0984074 100644 --- a/test/files/neg/reify_ann2a.scala +++ b/test/files/neg/reify_ann2a.scala @@ -26,5 +26,5 @@ object Test extends App { println(ttree.toString) // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/files/neg/reify_ann2b.scala b/test/files/neg/reify_ann2b.scala index 74273ad6ec..b43567c2a7 100644 --- a/test/files/neg/reify_ann2b.scala +++ b/test/files/neg/reify_ann2b.scala @@ -26,5 +26,5 @@ object Test extends App { println(ttree.toString) // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/files/run/reify_ann1a.scala b/test/files/run/reify_ann1a.scala index 933ea21b20..1ca170904b 100644 --- a/test/files/run/reify_ann1a.scala +++ b/test/files/run/reify_ann1a.scala @@ -26,5 +26,5 @@ object Test extends App { println(ttree.toString) // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/files/run/reify_ann1b.scala b/test/files/run/reify_ann1b.scala index 53dfe08086..9bdc712227 100644 --- a/test/files/run/reify_ann1b.scala +++ b/test/files/run/reify_ann1b.scala @@ -26,5 +26,5 @@ object Test extends App { println(ttree.toString) // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/files/run/reify_anonymous.scala b/test/files/run/reify_anonymous.scala index 1e7f3fe856..af16f2f8fd 100644 --- a/test/files/run/reify_anonymous.scala +++ b/test/files/run/reify_anonymous.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_classfileann_a.scala b/test/files/run/reify_classfileann_a.scala index 6bf4750bbc..c77bd3b8a2 100644 --- a/test/files/run/reify_classfileann_a.scala +++ b/test/files/run/reify_classfileann_a.scala @@ -20,5 +20,5 @@ object Test extends App { println(ttree.toString) // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/files/run/reify_closure1.scala b/test/files/run/reify_closure1.scala index 960f6aec3e..7cb3aff17d 100644 --- a/test/files/run/reify_closure1.scala +++ b/test/files/run/reify_closure1.scala @@ -10,8 +10,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure2a.scala b/test/files/run/reify_closure2a.scala index 6c28514c2b..cf367aa63f 100644 --- a/test/files/run/reify_closure2a.scala +++ b/test/files/run/reify_closure2a.scala @@ -10,8 +10,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure3a.scala b/test/files/run/reify_closure3a.scala index 4444c55ddf..d322b970b6 100644 --- a/test/files/run/reify_closure3a.scala +++ b/test/files/run/reify_closure3a.scala @@ -12,8 +12,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure4a.scala b/test/files/run/reify_closure4a.scala index 886e643a47..bbedd7e092 100644 --- a/test/files/run/reify_closure4a.scala +++ b/test/files/run/reify_closure4a.scala @@ -12,8 +12,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure5a.scala b/test/files/run/reify_closure5a.scala index 20994abff0..193e18103a 100644 --- a/test/files/run/reify_closure5a.scala +++ b/test/files/run/reify_closure5a.scala @@ -10,8 +10,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure6.scala b/test/files/run/reify_closure6.scala index 192c08f701..6aff83cb94 100644 --- a/test/files/run/reify_closure6.scala +++ b/test/files/run/reify_closure6.scala @@ -17,8 +17,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure7.scala b/test/files/run/reify_closure7.scala index 942c2cda9c..46002d8d6c 100644 --- a/test/files/run/reify_closure7.scala +++ b/test/files/run/reify_closure7.scala @@ -19,8 +19,7 @@ object Test extends App { if (clo == null) { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun.tree) clo = dyn.asInstanceOf[Int => Int] } diff --git a/test/files/run/reify_closure8a.scala b/test/files/run/reify_closure8a.scala index 5e54bfc8c7..805d8ff855 100644 --- a/test/files/run/reify_closure8a.scala +++ b/test/files/run/reify_closure8a.scala @@ -10,8 +10,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(10).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(10).fun.tree) val foo = dyn.asInstanceOf[Int] println(foo) } diff --git a/test/files/run/reify_closures10.scala b/test/files/run/reify_closures10.scala index d0f895ae4d..b6ec8e8911 100644 --- a/test/files/run/reify_closures10.scala +++ b/test/files/run/reify_closures10.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - println(toolbox.runExpr(ttree)) + println(toolbox.runExpr(code.tree)) } diff --git a/test/files/run/reify_complex.scala b/test/files/run/reify_complex.scala index aae4d558cf..0d9aeb28c5 100644 --- a/test/files/run/reify_complex.scala +++ b/test/files/run/reify_complex.scala @@ -26,6 +26,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_extendbuiltins.scala b/test/files/run/reify_extendbuiltins.scala index 57acd699ff..0aaec7cdf2 100644 --- a/test/files/run/reify_extendbuiltins.scala +++ b/test/files/run/reify_extendbuiltins.scala @@ -16,6 +16,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_for1.scala b/test/files/run/reify_for1.scala index 4b03330293..d1b60d878b 100644 --- a/test/files/run/reify_for1.scala +++ b/test/files/run/reify_for1.scala @@ -11,6 +11,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_fors.check b/test/files/run/reify_fors.check new file mode 100644 index 0000000000..eefddedc20 --- /dev/null +++ b/test/files/run/reify_fors.check @@ -0,0 +1,5 @@ +Persons over 20: John Richard +divisors(34) = List(1, 2, 17, 34) +findNums(15) = (4,1) (5,2) (6,1) (7,4) (8,3) (8,5) (9,2) (9,4) (10,1) (10,3) (10,7) (11,2) (11,6) (11,8) (12,1) (12,5) (12,7) (13,4) (13,6) (13,10) (14,3) (14,5) (14,9) +average(List(3.5, 5.0, 4.5)) = 4.333333333333333 +scalProd(List(3.5, 5.0, 4.5), List(2.0, 1.0, 3.0)) = 25.5 diff --git a/test/files/run/reify_fors.scala b/test/files/run/reify_fors.scala new file mode 100644 index 0000000000..27ee85d18b --- /dev/null +++ b/test/files/run/reify_fors.scala @@ -0,0 +1,106 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + object Persons { + /** A list of persons. To create a list, we use Predef.List + * which takes a variable number of arguments and constructs + * a list out of them. + */ + val persons = List( + new Person("Bob", 17), + new Person("John", 40), + new Person("Richard", 68) + ) + + /** A Person class. 'val' constructor parameters become + * public members of the class. + */ + class Person(val name: String, val age: Int) + + /** Return an iterator over persons that are older than 20. + */ + def olderThan20(xs: Seq[Person]): Iterator[String] = + olderThan20(xs.iterator) + + /** Return an iterator over persons older than 20, given + * an iterator over persons. + */ + def olderThan20(xs: Iterator[Person]): Iterator[String] = { + + // The first expression is called a 'generator' and makes + // 'p' take values from 'xs'. The second expression is + // called a 'filter' and it is a boolean expression which + // selects only persons older than 20. There can be more than + // one generator and filter. The 'yield' expression is evaluated + // for each 'p' which satisfies the filters and used to assemble + // the resulting iterator + for (p <- xs if p.age > 20) yield p.name + } + } + + /** Some functions over lists of numbers which demonstrate + * the use of for comprehensions. + */ + object Numeric { + + /** Return the divisors of n. */ + def divisors(n: Int): List[Int] = + for (i <- List.range(1, n+1) if n % i == 0) yield i + + /** Is 'n' a prime number? */ + def isPrime(n: Int) = divisors(n).length == 2 + + /** Return pairs of numbers whose sum is prime. */ + def findNums(n: Int): Iterable[(Int, Int)] = { + + // a for comprehension using two generators + for (i <- 1 until n; + j <- 1 until (i-1); + if isPrime(i + j)) yield (i, j) + } + + /** Return the sum of the elements of 'xs'. */ + def sum(xs: List[Double]): Double = + xs.foldLeft(0.0) { (x, y) => x + y } + + /** Return the sum of pairwise product of the two lists. */ + def scalProd(xs: List[Double], ys: List[Double]) = + sum(for((x, y) <- xs zip ys) yield x * y); + + /** Remove duplicate elements in 'xs'. */ + def removeDuplicates[A](xs: List[A]): List[A] = + if (xs.isEmpty) + xs + else + xs.head :: removeDuplicates(for (x <- xs.tail if x != xs.head) yield x) + } + + // import all members of object 'persons' in the current scope + import Persons._ + + print("Persons over 20:") + olderThan20(persons) foreach { x => print(" " + x) } + println + + import Numeric._ + + println("divisors(34) = " + divisors(34)) + + print("findNums(15) =") + findNums(15) foreach { x => print(" " + x) } + println + + val xs = List(3.5, 5.0, 4.5) + println("average(" + xs + ") = " + sum(xs) / xs.length) + + val ys = List(2.0, 1.0, 3.0) + println("scalProd(" + xs + ", " + ys +") = " + scalProd(xs, ys)) + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/files/run/reify_generic.scala b/test/files/run/reify_generic.scala index aef038b2d8..6a4ff148c4 100644 --- a/test/files/run/reify_generic.scala +++ b/test/files/run/reify_generic.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_generic2.scala b/test/files/run/reify_generic2.scala index d03fe7602b..9413f41eb5 100644 --- a/test/files/run/reify_generic2.scala +++ b/test/files/run/reify_generic2.scala @@ -11,6 +11,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_getter.scala b/test/files/run/reify_getter.scala index 83eaded506..33f36888a7 100644 --- a/test/files/run/reify_getter.scala +++ b/test/files/run/reify_getter.scala @@ -13,7 +13,6 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(code.tree) println("evaluated = " + evaluated) } diff --git a/test/files/run/reify_implicits.scala b/test/files/run/reify_implicits.scala index a15cef9c97..953eabe6c2 100644 --- a/test/files/run/reify_implicits.scala +++ b/test/files/run/reify_implicits.scala @@ -16,6 +16,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_inheritance.scala b/test/files/run/reify_inheritance.scala index 2a1b5f764f..78a64c264e 100644 --- a/test/files/run/reify_inheritance.scala +++ b/test/files/run/reify_inheritance.scala @@ -18,6 +18,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_inner1.scala b/test/files/run/reify_inner1.scala index 69931198e0..546fe36d16 100644 --- a/test/files/run/reify_inner1.scala +++ b/test/files/run/reify_inner1.scala @@ -17,6 +17,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_inner2.scala b/test/files/run/reify_inner2.scala index 0f12fd472a..613614b989 100644 --- a/test/files/run/reify_inner2.scala +++ b/test/files/run/reify_inner2.scala @@ -17,6 +17,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_inner3.scala b/test/files/run/reify_inner3.scala index 6b97b42b34..e9fb636dce 100644 --- a/test/files/run/reify_inner3.scala +++ b/test/files/run/reify_inner3.scala @@ -17,6 +17,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_inner4.scala b/test/files/run/reify_inner4.scala index de8c973b09..33870b0983 100644 --- a/test/files/run/reify_inner4.scala +++ b/test/files/run/reify_inner4.scala @@ -17,6 +17,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_maps.check b/test/files/run/reify_maps.check new file mode 100644 index 0000000000..08cbbb1359 --- /dev/null +++ b/test/files/run/reify_maps.check @@ -0,0 +1,4 @@ +red has code: 16711680 +Unknown color: green +Unknown color: blue +turquoise has code: 65535 diff --git a/test/files/run/reify_maps.scala b/test/files/run/reify_maps.scala new file mode 100644 index 0000000000..d3d95ffa24 --- /dev/null +++ b/test/files/run/reify_maps.scala @@ -0,0 +1,25 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + val colors = Map("red" -> 0xFF0000, + "turquoise" -> 0x00FFFF, + "black" -> 0x000000, + "orange" -> 0xFF8040, + "brown" -> 0x804000) + for (name <- List("red", "green", "blue", "turquoise")) println( + colors.get(name) match { + case Some(code) => + name + " has code: " + code + case None => + "Unknown color: " + name + } + ) + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/files/run/reify_printf.scala b/test/files/run/reify_printf.scala index 30901b98c2..cd6052bc5e 100644 --- a/test/files/run/reify_printf.scala +++ b/test/files/run/reify_printf.scala @@ -14,11 +14,10 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter, args mkString " ") - val ttree = toolbox.typeCheck(tree) val output = new ByteArrayOutputStream() Console.setOut(new PrintStream(output)) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(tree) assert(output.toString() == "hello world", output.toString() +" == hello world") diff --git a/test/files/run/reify_sort.scala b/test/files/run/reify_sort.scala index 42991fe5d2..5984a64967 100644 --- a/test/files/run/reify_sort.scala +++ b/test/files/run/reify_sort.scala @@ -52,6 +52,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_sort1.scala b/test/files/run/reify_sort1.scala index 42f4c824a5..6f365dea26 100644 --- a/test/files/run/reify_sort1.scala +++ b/test/files/run/reify_sort1.scala @@ -22,6 +22,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/reify_this.scala b/test/files/run/reify_this.scala index 44a25ae1b6..ee1f116013 100644 --- a/test/files/run/reify_this.scala +++ b/test/files/run/reify_this.scala @@ -11,8 +11,7 @@ trait Eval { val settings = new Settings val reporter = new ConsoleReporter(settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(tree) - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } } diff --git a/test/files/run/reify_timeofday.check b/test/files/run/reify_timeofday.check new file mode 100644 index 0000000000..3fd3b76a62 --- /dev/null +++ b/test/files/run/reify_timeofday.check @@ -0,0 +1 @@ +DateError diff --git a/test/files/run/reify_timeofday.scala b/test/files/run/reify_timeofday.scala new file mode 100644 index 0000000000..122d7a6d52 --- /dev/null +++ b/test/files/run/reify_timeofday.scala @@ -0,0 +1,47 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + class DateError extends Exception + + /** Simulating properties in Scala + * (example 4.2.1 in ScalaReference.pdf) + */ + class TimeOfDayVar { + private var h, m, s: Int = 0 + + def hours = h + + /** A method 'ident_=' is a setter for 'ident'. 'code.ident = ...' will + * be translated to a call to 'ident_=' + */ + def hours_= (h: Int) = + if (0 <= h && h < 24) this.h = h + else throw new DateError() + + def minutes = m + def minutes_= (m: Int) = + if (0 <= m && m < 60) this.m = m + else throw new DateError() + + def seconds = s + def seconds_= (s: Int) = + if (0 <= s && s < 60) this.s = s + else throw new DateError() + } + + val d = new TimeOfDayVar + d.hours = 8; d.minutes = 30; d.seconds = 0 + try { d.hours = 25 // throws a DateError exception + } catch { + case de: DateError => println("DateError") + case e: Exception => println("Exception") + } + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/files/run/reify_varargs.scala b/test/files/run/reify_varargs.scala index d38cbf2aac..175cfb5db0 100644 --- a/test/files/run/reify_varargs.scala +++ b/test/files/run/reify_varargs.scala @@ -12,6 +12,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5229_1.scala b/test/files/run/t5229_1.scala index 1d7bf0590b..d5af569656 100644 --- a/test/files/run/t5229_1.scala +++ b/test/files/run/t5229_1.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5229_2.check b/test/files/run/t5229_2.check index 5db6ec9b38..43c25b96af 100644 --- a/test/files/run/t5229_2.check +++ b/test/files/run/t5229_2.check @@ -1,2 +1,2 @@ 2 -evaluated = null +evaluated = () diff --git a/test/files/run/t5229_2.scala b/test/files/run/t5229_2.scala index 67be7328a6..07f9ac6b84 100644 --- a/test/files/run/t5229_2.scala +++ b/test/files/run/t5229_2.scala @@ -13,7 +13,6 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(code.tree) println("evaluated = " + evaluated) } diff --git a/test/files/run/t5230.check b/test/files/run/t5230.check index 5db6ec9b38..43c25b96af 100644 --- a/test/files/run/t5230.check +++ b/test/files/run/t5230.check @@ -1,2 +1,2 @@ 2 -evaluated = null +evaluated = () diff --git a/test/files/run/t5230.scala b/test/files/run/t5230.scala index 5aab8f9290..d3106ca05c 100644 --- a/test/files/run/t5230.scala +++ b/test/files/run/t5230.scala @@ -13,7 +13,6 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(code.tree) println("evaluated = " + evaluated) } diff --git a/test/files/run/t5258a.scala b/test/files/run/t5258a.scala index deabb8310f..8cc4249e06 100644 --- a/test/files/run/t5258a.scala +++ b/test/files/run/t5258a.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } \ No newline at end of file diff --git a/test/files/run/t5266_1.check b/test/files/run/t5266_1.check index 3feac16a0b..35f20802ee 100644 --- a/test/files/run/t5266_1.check +++ b/test/files/run/t5266_1.check @@ -1,2 +1,2 @@ 2 -evaluated = null \ No newline at end of file +evaluated = () \ No newline at end of file diff --git a/test/files/run/t5266_1.scala b/test/files/run/t5266_1.scala index 18e288e685..4262bc7a7b 100644 --- a/test/files/run/t5266_1.scala +++ b/test/files/run/t5266_1.scala @@ -10,7 +10,6 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(code.tree) println("evaluated = " + evaluated) } \ No newline at end of file diff --git a/test/files/run/t5266_2.check b/test/files/run/t5266_2.check index 3feac16a0b..35f20802ee 100644 --- a/test/files/run/t5266_2.check +++ b/test/files/run/t5266_2.check @@ -1,2 +1,2 @@ 2 -evaluated = null \ No newline at end of file +evaluated = () \ No newline at end of file diff --git a/test/files/run/t5266_2.scala b/test/files/run/t5266_2.scala index eb319583f8..d0f718dbd7 100644 --- a/test/files/run/t5266_2.scala +++ b/test/files/run/t5266_2.scala @@ -11,7 +11,6 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - val evaluated = toolbox.runExpr(ttree) + val evaluated = toolbox.runExpr(code.tree) println("evaluated = " + evaluated) } diff --git a/test/files/run/t5269.scala b/test/files/run/t5269.scala index a30509f3fe..cab99f17e6 100644 --- a/test/files/run/t5269.scala +++ b/test/files/run/t5269.scala @@ -17,6 +17,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5270.scala b/test/files/run/t5270.scala index 10f79790b0..934cc13dea 100644 --- a/test/files/run/t5270.scala +++ b/test/files/run/t5270.scala @@ -21,6 +21,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5271_1.check b/test/files/run/t5271_1.check index e69de29bb2..d4fd544e88 100644 --- a/test/files/run/t5271_1.check +++ b/test/files/run/t5271_1.check @@ -0,0 +1,11 @@ +{ + case class C extends Object with ScalaObject with Product with Serializable { + val foo : Int = _; + val bar : Int = _; + def (foo: Int, bar: Int) = { + super.(); + () + } + }; + () +} diff --git a/test/files/run/t5271_1.scala b/test/files/run/t5271_1.scala index 5f10e64528..fbc57aead7 100644 --- a/test/files/run/t5271_1.scala +++ b/test/files/run/t5271_1.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + println(code.tree) } diff --git a/test/files/run/t5271_2.check b/test/files/run/t5271_2.check index b8626c4cff..5a519f265f 100644 --- a/test/files/run/t5271_2.check +++ b/test/files/run/t5271_2.check @@ -1 +1,12 @@ -4 +{ + case class C extends Object with ScalaObject with Product with Serializable { + val foo : Int = _; + val bar : Int = _; + def (foo: Int, bar: Int) = { + super.(); + () + } + }; + val c = C.apply(2, 2); + scala.this.Predef.println(c.foo.$times(c.bar)) +} diff --git a/test/files/run/t5271_2.scala b/test/files/run/t5271_2.scala index 71967c04ed..4bfc574e00 100644 --- a/test/files/run/t5271_2.scala +++ b/test/files/run/t5271_2.scala @@ -11,6 +11,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + println(code.tree) } diff --git a/test/files/run/t5271_3.check b/test/files/run/t5271_3.check index f32a5804e2..be87696f02 100644 --- a/test/files/run/t5271_3.check +++ b/test/files/run/t5271_3.check @@ -1 +1,19 @@ -true \ No newline at end of file +{ + object C extends Object with ScalaObject with Serializable { + def () = { + super.(); + () + }; + def qwe: Int = 4 + }; + case class C extends Object with ScalaObject with Product with Serializable { + val foo : Int = _; + val bar : Int = _; + def (foo: Int, bar: Int) = { + super.(); + () + } + }; + val c = C.apply(2, 2); + scala.this.Predef.println(c.foo.$times(c.bar).$eq$eq(C.qwe)) +} diff --git a/test/files/run/t5271_3.scala b/test/files/run/t5271_3.scala index bfa116c691..a085bdca4c 100644 --- a/test/files/run/t5271_3.scala +++ b/test/files/run/t5271_3.scala @@ -12,6 +12,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + println(code.tree) } diff --git a/test/files/run/t5271_4.scala b/test/files/run/t5271_4.scala index e5e16033e8..c253b1adca 100644 --- a/test/files/run/t5271_4.scala +++ b/test/files/run/t5271_4.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5272_1.scala b/test/files/run/t5272_1.scala index 3f44d05fb3..882287f033 100644 --- a/test/files/run/t5272_1.scala +++ b/test/files/run/t5272_1.scala @@ -12,6 +12,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5272_2.scala b/test/files/run/t5272_2.scala index 833ee65285..48b6a670bb 100644 --- a/test/files/run/t5272_2.scala +++ b/test/files/run/t5272_2.scala @@ -11,6 +11,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5273_1.scala b/test/files/run/t5273_1.scala index 1175881c9f..80460a4ae6 100644 --- a/test/files/run/t5273_1.scala +++ b/test/files/run/t5273_1.scala @@ -12,6 +12,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5273_2a.scala b/test/files/run/t5273_2a.scala index 12ddbb280a..a7a336d8a7 100644 --- a/test/files/run/t5273_2a.scala +++ b/test/files/run/t5273_2a.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5273_2b.scala b/test/files/run/t5273_2b.scala index 8b75084463..85c40f0607 100644 --- a/test/files/run/t5273_2b.scala +++ b/test/files/run/t5273_2b.scala @@ -11,6 +11,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5274_1.scala b/test/files/run/t5274_1.scala index c501172518..74a5b81bcb 100644 --- a/test/files/run/t5274_1.scala +++ b/test/files/run/t5274_1.scala @@ -15,6 +15,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5274_2.scala b/test/files/run/t5274_2.scala index 42991fe5d2..5984a64967 100644 --- a/test/files/run/t5274_2.scala +++ b/test/files/run/t5274_2.scala @@ -52,6 +52,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5275.scala b/test/files/run/t5275.scala index d419834ded..285d8a18a4 100644 --- a/test/files/run/t5275.scala +++ b/test/files/run/t5275.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5276_1a.scala b/test/files/run/t5276_1a.scala index c8afbba19e..b717675824 100644 --- a/test/files/run/t5276_1a.scala +++ b/test/files/run/t5276_1a.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5276_1b.scala b/test/files/run/t5276_1b.scala index 31582201fb..1ff25504ca 100644 --- a/test/files/run/t5276_1b.scala +++ b/test/files/run/t5276_1b.scala @@ -5,11 +5,10 @@ import reflect.runtime.Mirror.ToolBox object Test extends App { val code = scala.reflect.Code.lift{ implicit lazy val x = 2 - implicitly[Int] + println(implicitly[Int]) }; val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5276_2a.scala b/test/files/run/t5276_2a.scala index 179c14b739..af5ff2a565 100644 --- a/test/files/run/t5276_2a.scala +++ b/test/files/run/t5276_2a.scala @@ -13,6 +13,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5276_2b.scala b/test/files/run/t5276_2b.scala index 6fe2873fef..63904b2898 100644 --- a/test/files/run/t5276_2b.scala +++ b/test/files/run/t5276_2b.scala @@ -14,6 +14,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5277_1.scala b/test/files/run/t5277_1.scala index 57acd699ff..0aaec7cdf2 100644 --- a/test/files/run/t5277_1.scala +++ b/test/files/run/t5277_1.scala @@ -16,6 +16,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5277_2.scala b/test/files/run/t5277_2.scala index 67b6b000bc..91ed55122a 100644 --- a/test/files/run/t5277_2.scala +++ b/test/files/run/t5277_2.scala @@ -13,6 +13,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5279.scala b/test/files/run/t5279.scala index 39e7dd2c66..cef58535d5 100644 --- a/test/files/run/t5279.scala +++ b/test/files/run/t5279.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/files/run/t5334_1.check b/test/files/run/t5334_1.check index e09aedaede..96d80cd6c4 100644 --- a/test/files/run/t5334_1.check +++ b/test/files/run/t5334_1.check @@ -1,2 +1 @@ -C C \ No newline at end of file diff --git a/test/files/run/t5334_1.scala b/test/files/run/t5334_1.scala index 7acf282bb8..9887bebf78 100644 --- a/test/files/run/t5334_1.scala +++ b/test/files/run/t5334_1.scala @@ -10,7 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - println(ttree.tpe) - println(toolbox.runExpr(ttree)) + println(toolbox.runExpr(code.tree)) } diff --git a/test/files/run/t5334_2.check b/test/files/run/t5334_2.check index 2ae76754c0..613d286a18 100644 --- a/test/files/run/t5334_2.check +++ b/test/files/run/t5334_2.check @@ -1,2 +1 @@ -List[(C, C)] List((C,C)) \ No newline at end of file diff --git a/test/files/run/t5334_2.scala b/test/files/run/t5334_2.scala index 26f0778400..775a05aaf7 100644 --- a/test/files/run/t5334_2.scala +++ b/test/files/run/t5334_2.scala @@ -10,7 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - println(ttree.tpe) - println(toolbox.runExpr(ttree)) + println(toolbox.runExpr(code.tree)) } diff --git a/test/files/run/t5335.scala b/test/files/run/t5335.scala index 9a8b91f04d..8e2ed59db6 100644 --- a/test/files/run/t5335.scala +++ b/test/files/run/t5335.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_addressbook.scala b/test/pending/run/reify_addressbook.scala index 225f26b75e..54dd5545bd 100644 --- a/test/pending/run/reify_addressbook.scala +++ b/test/pending/run/reify_addressbook.scala @@ -66,6 +66,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_brainf_ck.scala b/test/pending/run/reify_brainf_ck.scala index 3bfb76c9ea..0034644b81 100644 --- a/test/pending/run/reify_brainf_ck.scala +++ b/test/pending/run/reify_brainf_ck.scala @@ -80,6 +80,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_callccinterpreter.scala b/test/pending/run/reify_callccinterpreter.scala index c10f4f0b4e..96ae9c5c17 100644 --- a/test/pending/run/reify_callccinterpreter.scala +++ b/test/pending/run/reify_callccinterpreter.scala @@ -89,6 +89,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_classfileann_b.scala b/test/pending/run/reify_classfileann_b.scala index b76dd8fc9f..c31826377a 100644 --- a/test/pending/run/reify_classfileann_b.scala +++ b/test/pending/run/reify_classfileann_b.scala @@ -17,12 +17,8 @@ object Test extends App { }.tree println(tree.toString) - // test 2: import and typecheck + // test 2: import and compile val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(tree) - println(ttree.toString) - - // test 3: import and compile - toolbox.runExpr(ttree) + toolbox.runExpr(tree) } \ No newline at end of file diff --git a/test/pending/run/reify_closure2b.scala b/test/pending/run/reify_closure2b.scala index a1fead07ae..b9c0063290 100644 --- a/test/pending/run/reify_closure2b.scala +++ b/test/pending/run/reify_closure2b.scala @@ -12,8 +12,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(y).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(y).fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/pending/run/reify_closure3b.scala b/test/pending/run/reify_closure3b.scala index acf07c4749..8f161dbff3 100644 --- a/test/pending/run/reify_closure3b.scala +++ b/test/pending/run/reify_closure3b.scala @@ -14,8 +14,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(y).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(y).fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/pending/run/reify_closure4b.scala b/test/pending/run/reify_closure4b.scala index ed102298c5..238795d4dd 100644 --- a/test/pending/run/reify_closure4b.scala +++ b/test/pending/run/reify_closure4b.scala @@ -14,8 +14,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(y).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(y).fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/pending/run/reify_closure5b.scala b/test/pending/run/reify_closure5b.scala index 29e911538f..bdb2583e8a 100644 --- a/test/pending/run/reify_closure5b.scala +++ b/test/pending/run/reify_closure5b.scala @@ -12,8 +12,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(ys).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(ys).fun.tree) dyn.asInstanceOf[Int => Int] } diff --git a/test/pending/run/reify_closure8b.scala b/test/pending/run/reify_closure8b.scala index 9e37e4e09a..38031c217b 100644 --- a/test/pending/run/reify_closure8b.scala +++ b/test/pending/run/reify_closure8b.scala @@ -10,8 +10,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(10).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(10).fun.tree) val foo = dyn.asInstanceOf[Int] println(foo) } diff --git a/test/pending/run/reify_closure9a.scala b/test/pending/run/reify_closure9a.scala index f3ee153d3c..185f4ffca1 100644 --- a/test/pending/run/reify_closure9a.scala +++ b/test/pending/run/reify_closure9a.scala @@ -11,8 +11,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(y).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(y).fun.tree) dyn.asInstanceOf[Int] } diff --git a/test/pending/run/reify_closure9b.scala b/test/pending/run/reify_closure9b.scala index 8d349e8701..ad279fac6d 100644 --- a/test/pending/run/reify_closure9b.scala +++ b/test/pending/run/reify_closure9b.scala @@ -11,8 +11,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(new Foo(y).fun.tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(new Foo(y).fun.tree) dyn.asInstanceOf[Int] } diff --git a/test/pending/run/reify_closures11.scala b/test/pending/run/reify_closures11.scala index 42053bd029..2c4177b8f2 100644 --- a/test/pending/run/reify_closures11.scala +++ b/test/pending/run/reify_closures11.scala @@ -11,8 +11,7 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(fun().tree) - val dyn = toolbox.runExpr(ttree) + val dyn = toolbox.runExpr(fun().tree) val foo = dyn.asInstanceOf[Int] println(foo) } diff --git a/test/pending/run/reify_csv.scala b/test/pending/run/reify_csv.scala index a05a3b55d4..a6a616fab0 100644 --- a/test/pending/run/reify_csv.scala +++ b/test/pending/run/reify_csv.scala @@ -37,6 +37,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_fors.check b/test/pending/run/reify_fors.check deleted file mode 100644 index eefddedc20..0000000000 --- a/test/pending/run/reify_fors.check +++ /dev/null @@ -1,5 +0,0 @@ -Persons over 20: John Richard -divisors(34) = List(1, 2, 17, 34) -findNums(15) = (4,1) (5,2) (6,1) (7,4) (8,3) (8,5) (9,2) (9,4) (10,1) (10,3) (10,7) (11,2) (11,6) (11,8) (12,1) (12,5) (12,7) (13,4) (13,6) (13,10) (14,3) (14,5) (14,9) -average(List(3.5, 5.0, 4.5)) = 4.333333333333333 -scalProd(List(3.5, 5.0, 4.5), List(2.0, 1.0, 3.0)) = 25.5 diff --git a/test/pending/run/reify_fors.scala b/test/pending/run/reify_fors.scala deleted file mode 100644 index f3556514a9..0000000000 --- a/test/pending/run/reify_fors.scala +++ /dev/null @@ -1,107 +0,0 @@ -import scala.tools.nsc.reporters._ -import scala.tools.nsc.Settings -import reflect.runtime.Mirror.ToolBox - -object Test extends App { - val code = scala.reflect.Code.lift{ - object Persons { - /** A list of persons. To create a list, we use Predef.List - * which takes a variable number of arguments and constructs - * a list out of them. - */ - val persons = List( - new Person("Bob", 17), - new Person("John", 40), - new Person("Richard", 68) - ) - - /** A Person class. 'val' constructor parameters become - * public members of the class. - */ - class Person(val name: String, val age: Int) - - /** Return an iterator over persons that are older than 20. - */ - def olderThan20(xs: Seq[Person]): Iterator[String] = - olderThan20(xs.elements) - - /** Return an iterator over persons older than 20, given - * an iterator over persons. - */ - def olderThan20(xs: Iterator[Person]): Iterator[String] = { - - // The first expression is called a 'generator' and makes - // 'p' take values from 'xs'. The second expression is - // called a 'filter' and it is a boolean expression which - // selects only persons older than 20. There can be more than - // one generator and filter. The 'yield' expression is evaluated - // for each 'p' which satisfies the filters and used to assemble - // the resulting iterator - for (p <- xs if p.age > 20) yield p.name - } - } - - /** Some functions over lists of numbers which demonstrate - * the use of for comprehensions. - */ - object Numeric { - - /** Return the divisors of n. */ - def divisors(n: Int): List[Int] = - for (i <- List.range(1, n+1) if n % i == 0) yield i - - /** Is 'n' a prime number? */ - def isPrime(n: Int) = divisors(n).length == 2 - - /** Return pairs of numbers whose sum is prime. */ - def findNums(n: Int): Iterable[(Int, Int)] = { - - // a for comprehension using two generators - for (i <- 1 until n; - j <- 1 until (i-1); - if isPrime(i + j)) yield (i, j) - } - - /** Return the sum of the elements of 'xs'. */ - def sum(xs: List[Double]): Double = - xs.foldLeft(0.0) { (x, y) => x + y } - - /** Return the sum of pairwise product of the two lists. */ - def scalProd(xs: List[Double], ys: List[Double]) = - sum(for((x, y) <- xs zip ys) yield x * y); - - /** Remove duplicate elements in 'xs'. */ - def removeDuplicates[A](xs: List[A]): List[A] = - if (xs.isEmpty) - xs - else - xs.head :: removeDuplicates(for (x <- xs.tail if x != xs.head) yield x) - } - - // import all members of object 'persons' in the current scope - import Persons._ - - print("Persons over 20:") - olderThan20(persons) foreach { x => print(" " + x) } - println - - import Numeric._ - - println("divisors(34) = " + divisors(34)) - - print("findNums(15) =") - findNums(15) foreach { x => print(" " + x) } - println - - val xs = List(3.5, 5.0, 4.5) - println("average(" + xs + ") = " + sum(xs) / xs.length) - - val ys = List(2.0, 1.0, 3.0) - println("scalProd(" + xs + ", " + ys +") = " + scalProd(xs, ys)) - }; - - val reporter = new ConsoleReporter(new Settings) - val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) -} diff --git a/test/pending/run/reify_gadts.scala b/test/pending/run/reify_gadts.scala index 7077de735c..9feb7a5726 100644 --- a/test/pending/run/reify_gadts.scala +++ b/test/pending/run/reify_gadts.scala @@ -40,6 +40,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_lazyevaluation.scala b/test/pending/run/reify_lazyevaluation.scala index f38af76751..0720a7c979 100644 --- a/test/pending/run/reify_lazyevaluation.scala +++ b/test/pending/run/reify_lazyevaluation.scala @@ -60,6 +60,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_maps.check b/test/pending/run/reify_maps.check deleted file mode 100644 index 08cbbb1359..0000000000 --- a/test/pending/run/reify_maps.check +++ /dev/null @@ -1,4 +0,0 @@ -red has code: 16711680 -Unknown color: green -Unknown color: blue -turquoise has code: 65535 diff --git a/test/pending/run/reify_maps.scala b/test/pending/run/reify_maps.scala deleted file mode 100644 index 589b28d049..0000000000 --- a/test/pending/run/reify_maps.scala +++ /dev/null @@ -1,26 +0,0 @@ -import scala.tools.nsc.reporters._ -import scala.tools.nsc.Settings -import reflect.runtime.Mirror.ToolBox - -object Test extends App { - val code = scala.reflect.Code.lift{ - val colors = Map("red" -> 0xFF0000, - "turquoise" -> 0x00FFFF, - "black" -> 0x000000, - "orange" -> 0xFF8040, - "brown" -> 0x804000) - for (name <- List("red", "green", "blue", "turquoise")) println( - colors.get(name) match { - case Some(code) => - name + " has code: " + code - case None => - "Unknown color: " + name - } - ) - }; - - val reporter = new ConsoleReporter(new Settings) - val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) -} diff --git a/test/pending/run/reify_properties.scala b/test/pending/run/reify_properties.scala index 2115a96715..265c344b8e 100644 --- a/test/pending/run/reify_properties.scala +++ b/test/pending/run/reify_properties.scala @@ -58,6 +58,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_simpleinterpreter.scala b/test/pending/run/reify_simpleinterpreter.scala index b39f5583bb..4762afb3cc 100644 --- a/test/pending/run/reify_simpleinterpreter.scala +++ b/test/pending/run/reify_simpleinterpreter.scala @@ -77,6 +77,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } diff --git a/test/pending/run/reify_timeofday.check b/test/pending/run/reify_timeofday.check deleted file mode 100644 index 3fd3b76a62..0000000000 --- a/test/pending/run/reify_timeofday.check +++ /dev/null @@ -1 +0,0 @@ -DateError diff --git a/test/pending/run/reify_timeofday.scala b/test/pending/run/reify_timeofday.scala deleted file mode 100644 index 6bd11b0d30..0000000000 --- a/test/pending/run/reify_timeofday.scala +++ /dev/null @@ -1,48 +0,0 @@ -import scala.tools.nsc.reporters._ -import scala.tools.nsc.Settings -import reflect.runtime.Mirror.ToolBox - -object Test extends App { - val code = scala.reflect.Code.lift{ - class DateError extends Exception - - /** Simulating properties in Scala - * (example 4.2.1 in ScalaReference.pdf) - */ - class TimeOfDayVar { - private var h, m, s: Int = 0 - - def hours = h - - /** A method 'ident_=' is a setter for 'ident'. 'code.ident = ...' will - * be translated to a call to 'ident_=' - */ - def hours_= (h: Int) = - if (0 <= h && h < 24) this.h = h - else throw new DateError() - - def minutes = m - def minutes_= (m: Int) = - if (0 <= m && m < 60) this.m = m - else throw new DateError() - - def seconds = s - def seconds_= (s: Int) = - if (0 <= s && s < 60) this.s = s - else throw new DateError() - } - - val d = new TimeOfDayVar - d.hours = 8; d.minutes = 30; d.seconds = 0 - try { d.hours = 25 // throws a DateError exception - } catch { - case de: DateError => println("DateError") - case e: Exception => println("Exception") - } - }; - - val reporter = new ConsoleReporter(new Settings) - val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) -} diff --git a/test/pending/run/t5258b.scala b/test/pending/run/t5258b.scala index 70cb4a7f4e..3a603095b3 100644 --- a/test/pending/run/t5258b.scala +++ b/test/pending/run/t5258b.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } \ No newline at end of file diff --git a/test/pending/run/t5258c.scala b/test/pending/run/t5258c.scala index a93170d0d6..b0d16ba0b1 100644 --- a/test/pending/run/t5258c.scala +++ b/test/pending/run/t5258c.scala @@ -10,6 +10,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } \ No newline at end of file diff --git a/test/pending/run/t5271_1.check b/test/pending/run/t5271_1.check new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/pending/run/t5271_1.scala b/test/pending/run/t5271_1.scala new file mode 100644 index 0000000000..afbd8fe465 --- /dev/null +++ b/test/pending/run/t5271_1.scala @@ -0,0 +1,13 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + case class C(foo: Int, bar: Int) + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/pending/run/t5271_2.check b/test/pending/run/t5271_2.check new file mode 100644 index 0000000000..b8626c4cff --- /dev/null +++ b/test/pending/run/t5271_2.check @@ -0,0 +1 @@ +4 diff --git a/test/pending/run/t5271_2.scala b/test/pending/run/t5271_2.scala new file mode 100644 index 0000000000..d85d945973 --- /dev/null +++ b/test/pending/run/t5271_2.scala @@ -0,0 +1,15 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + case class C(foo: Int, bar: Int) + val c = C(2, 2) + println(c.foo * c.bar) + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/pending/run/t5271_3.check b/test/pending/run/t5271_3.check new file mode 100644 index 0000000000..f32a5804e2 --- /dev/null +++ b/test/pending/run/t5271_3.check @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/test/pending/run/t5271_3.scala b/test/pending/run/t5271_3.scala new file mode 100644 index 0000000000..5a624de903 --- /dev/null +++ b/test/pending/run/t5271_3.scala @@ -0,0 +1,16 @@ +import scala.tools.nsc.reporters._ +import scala.tools.nsc.Settings +import reflect.runtime.Mirror.ToolBox + +object Test extends App { + val code = scala.reflect.Code.lift{ + object C { def qwe = 4 } + case class C(foo: Int, bar: Int) + val c = C(2, 2) + println(c.foo * c.bar == C.qwe) + }; + + val reporter = new ConsoleReporter(new Settings) + val toolbox = new ToolBox(reporter) + toolbox.runExpr(code.tree) +} diff --git a/test/pending/run/t5418.scala b/test/pending/run/t5418.scala index 065710f15e..fe813cf5ae 100644 --- a/test/pending/run/t5418.scala +++ b/test/pending/run/t5418.scala @@ -9,6 +9,5 @@ object Test extends App { val reporter = new ConsoleReporter(new Settings) val toolbox = new ToolBox(reporter) - val ttree = toolbox.typeCheck(code.tree) - toolbox.runExpr(ttree) + toolbox.runExpr(code.tree) } \ No newline at end of file -- cgit v1.2.3 From 9655fafbc89b650b92f239aa7f69df7a16e3542b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 15 Feb 2012 12:14:43 -0800 Subject: Revert "Make fix for SI-5452 not break other things." This reverts commit a725bf982c06e16c5d533ea6b2227b726db4f7e4. --- src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 4 +++- src/compiler/scala/tools/nsc/typechecker/Infer.scala | 7 +------ test/files/neg/t5452.check | 4 +--- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 6ee09d064f..466b5125a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -714,9 +714,11 @@ trait ContextErrors { setError(tree) } - def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + setError(tree) + } def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, argtpes: List[Type], pt: Type) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index acf905d974..b97fbebec2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1466,9 +1466,7 @@ trait Infer { argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 - var secondTry = true tryTwice { - secondTry = !secondTry debuglog("infer method alt "+ tree.symbol +" with alternatives "+ (alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt) @@ -1490,11 +1488,8 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) { + if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt) - if (secondTry) - setError(tree) - } else inferMethodAlternative(tree, undetparams, argtpes, WildcardType) } else if (!competing.isEmpty) { diff --git a/test/files/neg/t5452.check b/test/files/neg/t5452.check index 2f35a45509..baf544499b 100644 --- a/test/files/neg/t5452.check +++ b/test/files/neg/t5452.check @@ -1,7 +1,5 @@ t5452.scala:28: error: overloaded method value apply with alternatives: - ()Queryable[CoffeesTable] - (t: Tree)(implicit evidence$2: Manifest[CoffeesTable])Nothing - (implicit evidence$1: Manifest[CoffeesTable])Nothing + cannot be applied to (Queryable[CoffeesTable]) Queryable[CoffeesTable]( q.treeFilter(null) ) ^ -- cgit v1.2.3 From 6543b2d983a4e44ad9bd2ea036d53ce52c37284c Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 15 Feb 2012 12:14:49 -0800 Subject: Revert "Fix for SI-5452." This reverts commit 2b731911e97a281e324060099631e2374b2144ec. --- .../tools/nsc/typechecker/ContextErrors.scala | 4 +-- test/files/neg/t5452.check | 6 ----- test/files/neg/t5452.scala | 29 ---------------------- 3 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 test/files/neg/t5452.check delete mode 100644 test/files/neg/t5452.scala (limited to 'test/files/neg') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 466b5125a8..6ee09d064f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -714,11 +714,9 @@ trait ContextErrors { setError(tree) } - def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) - setError(tree) - } def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, argtpes: List[Type], pt: Type) = { diff --git a/test/files/neg/t5452.check b/test/files/neg/t5452.check deleted file mode 100644 index baf544499b..0000000000 --- a/test/files/neg/t5452.check +++ /dev/null @@ -1,6 +0,0 @@ -t5452.scala:28: error: overloaded method value apply with alternatives: - - cannot be applied to (Queryable[CoffeesTable]) - Queryable[CoffeesTable]( q.treeFilter(null) ) - ^ -one error found diff --git a/test/files/neg/t5452.scala b/test/files/neg/t5452.scala deleted file mode 100644 index 1032db7a4b..0000000000 --- a/test/files/neg/t5452.scala +++ /dev/null @@ -1,29 +0,0 @@ -// /scala/trac/5452/a.scala -// Mon Feb 13 22:52:36 PST 2012 - -// import scala.reflect.mirror._ - -trait Tree - -object Bip { - def ??? = sys.error("") -} -import Bip._ - -case class Queryable[T]() { - def treeFilter( t:Tree ) : Queryable[T] = ??? -} - -object Queryable { - def apply[T:Manifest] = ??? - def apply[T:Manifest]( t:Tree ) = ??? -} - -trait CoffeesTable{ - def sales : Int -} - -object Test extends App{ - val q = new Queryable[CoffeesTable] - Queryable[CoffeesTable]( q.treeFilter(null) ) -} -- cgit v1.2.3