summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala14
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala16
-rw-r--r--test/files/jvm/annotations.check11
-rw-r--r--test/files/jvm/annotations.scala31
-rw-r--r--test/files/pos/t3177.scala39
-rw-r--r--test/files/pos/t3373.scala11
6 files changed, 72 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 9a6c4cc401..e503d721f9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -520,7 +520,7 @@ self: Analyzer =>
* - the symbol's type is initialized
* - the symbol comes from a classfile
* - the symbol comes from a different sourcefile than the current one
- * - the symbol's definition comes before, and does not contain the closest enclosing definition,
+ * - the symbol and the accessed symbol's definitions come before, and do not contain the closest enclosing definition, // see #3373
* - the symbol's definition is a val, var, or def with an explicit result type
* The aim of this method is to prevent premature cyclic reference errors
* by computing the types of only those implicits for which one of these
@@ -539,9 +539,15 @@ self: Analyzer =>
case _ => true
}
}
- def comesBefore(sym: Symbol, owner: Symbol) =
- sym.pos.pointOrElse(0) < owner.pos.pointOrElse(Integer.MAX_VALUE) &&
- !(owner.ownerChain contains sym)
+ def comesBefore(sym: Symbol, owner: Symbol) = {
+ val ownerPos = owner.pos.pointOrElse(Integer.MAX_VALUE)
+ sym.pos.pointOrElse(0) < ownerPos && (
+ if(sym isGetterOrSetter) {
+ val symAcc = sym.accessed // #3373
+ symAcc.pos.pointOrElse(0) < ownerPos &&
+ !(owner.ownerChain exists (o => (o eq sym) || (o eq symAcc))) // probably faster to iterate only once, don't feel like duplicating hasTransOwner for this case
+ } else !(owner hasTransOwner sym)) // faster than owner.ownerChain contains sym
+ }
sym.isInitialized ||
sym.sourceFile == null ||
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index f503a797bb..92dd368ac5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1330,9 +1330,7 @@ trait Typers { self: Analyzer =>
val value = stat.symbol
val allAnnots = value.annotations
if (!isDeferred)
- // keepClean: by default annotations go to the field, except if the field is
- // generated for a class parameter (PARAMACCESSOR).
- value.setAnnotations(memberAnnots(allAnnots, FieldTargetClass, keepClean = !mods.hasFlag(PARAMACCESSOR)))
+ value.setAnnotations(memberAnnots(allAnnots, FieldTargetClass))
val getter = if (isDeferred) value else value.getter(value.owner)
assert(getter != NoSymbol, stat)
@@ -1412,12 +1410,10 @@ trait Typers { self: Analyzer =>
List(stat)
}
- /**
- * The annotations amongst `annots` that should go on a member of class
- * `memberClass` (field, getter, setter, beanGetter, beanSetter, param)
- * If 'keepClean' is true, annotations without any meta-annotation are kept
+ /** The annotations amongst `annots` that should go on a member of class
+ * `memberClass` (field, getter, setter, beanGetter, beanSetter, param)
*/
- protected def memberAnnots(annots: List[AnnotationInfo], memberClass: Symbol, keepClean: Boolean = false) = {
+ protected def memberAnnots(annots: List[AnnotationInfo], memberClass: Symbol) = {
def hasMatching(metaAnnots: List[AnnotationInfo], orElse: => Boolean) = {
// either one of the meta-annotations matches the `memberClass`
@@ -1434,7 +1430,7 @@ trait Typers { self: Analyzer =>
// there was no meta-annotation on `ann`. Look if the class annotations of
// `ann` has a `target` annotation, otherwise put `ann` only on fields.
def noMetaAnnot(ann: AnnotationInfo) = {
- hasMatching(ann.atp.typeSymbol.annotations, keepClean)
+ hasMatching(ann.atp.typeSymbol.annotations, memberClass == FieldTargetClass)
}
annots.filter(ann => ann.atp match {
@@ -1706,7 +1702,7 @@ trait Typers { self: Analyzer =>
for (vparams <- ddef.vparamss; vd <- vparams) {
if (vd hasFlag PARAMACCESSOR) {
val sym = vd.symbol
- sym.setAnnotations(memberAnnots(sym.annotations, ParamTargetClass, keepClean = true))
+ sym.setAnnotations(memberAnnots(sym.annotations, ParamTargetClass))
}
}
}
diff --git a/test/files/jvm/annotations.check b/test/files/jvm/annotations.check
index fe14289381..128f8e8f6e 100644
--- a/test/files/jvm/annotations.check
+++ b/test/files/jvm/annotations.check
@@ -23,7 +23,7 @@ public Test4$Foo6(java.lang.String)
public Test4$Foo7()
@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=constructor val)
-public Test4$Foo8(int)
+private final int Test4$Foo8.n
@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=http://eppli.com)
private int Test4$Foo9.z
@@ -37,14 +37,5 @@ public int Test4$Foo9.x()
@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=http://uppla.com)
public void Test4$Foo9.setY(int)
-@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=on param 1)
-public Test4$Foo10(java.lang.String)
-
-@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=on param 2)
-private final java.lang.String Test4$Foo11.name
-
-@test.SourceAnnotation(mails={bill.gates@bloodsuckers.com}, value=on param 3)
-public void Test4$Foo12.name_$eq(java.lang.String)
-
0
99
diff --git a/test/files/jvm/annotations.scala b/test/files/jvm/annotations.scala
index 136aae6675..12760beb4e 100644
--- a/test/files/jvm/annotations.scala
+++ b/test/files/jvm/annotations.scala
@@ -102,29 +102,18 @@ object Test4 {
type myAnn = SourceAnnotation @beanGetter @field
@BeanProperty @myAnn("http://eppli.com") var z = 0
}
- class Foo10(@SourceAnnotation("on param 1") val name: String)
- class Foo11(@(SourceAnnotation @scala.annotation.target.field)("on param 2") val name: String)
- class Foo12(@(SourceAnnotation @scala.annotation.target.setter)("on param 3") var name: String)
def run {
import java.lang.annotation.Annotation
import java.lang.reflect.AnnotatedElement
- def printSourceAnnotation(a: Annotation) {
- val ann = a.asInstanceOf[SourceAnnotation]
- println("@test.SourceAnnotation(mails=" + ann.mails.deepMkString("{", ",", "}") +
- ", value=" + ann.value + ")")
- }
def printSourceAnnotations(target: AnnotatedElement) {
//print SourceAnnotation in a predefined way to insure
// against difference in the JVMs (e.g. Sun's vs IBM's)
- val anns = target.getAnnotations()
- anns foreach printSourceAnnotation
- if (anns.length > 0) {
- println(target)
- println
+ def printSourceAnnotation(a: Annotation) {
+ val ann = a.asInstanceOf[SourceAnnotation]
+ println("@test.SourceAnnotation(mails=" + ann.mails.deepMkString("{", ",", "}") +
+ ", value=" + ann.value + ")")
}
- }
- def printParamSourceAnnotations(target: { def getParameterAnnotations(): Array[Array[Annotation]] }) {
- val anns = target.getParameterAnnotations().flatten
+ val anns = target.getAnnotations()
anns foreach printSourceAnnotation
if (anns.length > 0) {
println(target)
@@ -141,18 +130,8 @@ object Test4 {
classOf[Foo7].getDeclaredConstructors foreach printSourceAnnotations
classOf[Foo8].getDeclaredFields foreach printSourceAnnotations
classOf[Foo8].getDeclaredMethods foreach printSourceAnnotations
- classOf[Foo8].getDeclaredConstructors foreach printParamSourceAnnotations
classOf[Foo9].getDeclaredFields.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
classOf[Foo9].getDeclaredMethods.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo10].getDeclaredFields.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo10].getDeclaredMethods.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo10].getDeclaredConstructors foreach printParamSourceAnnotations
- classOf[Foo11].getDeclaredFields.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo11].getDeclaredMethods.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo11].getDeclaredConstructors foreach printParamSourceAnnotations
- classOf[Foo12].getDeclaredFields.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo12].getDeclaredMethods.sortWith((x, y) => x.toString < y.toString) foreach printSourceAnnotations
- classOf[Foo12].getDeclaredConstructors foreach printParamSourceAnnotations
}
}
diff --git a/test/files/pos/t3177.scala b/test/files/pos/t3177.scala
new file mode 100644
index 0000000000..9f9528faec
--- /dev/null
+++ b/test/files/pos/t3177.scala
@@ -0,0 +1,39 @@
+trait InvariantFunctor[F[_]] {
+ def xmap[A, B](ma: F[A], f: A => B, g: B => A): F[B]
+}
+
+object InvariantFunctor {
+ import Endo._
+
+ implicit val EndoInvariantFunctor = new InvariantFunctor[Endo] {
+ def xmap[A, B](ma: Endo[A], f: A => B, g: B => A): Endo[B] = (b: B) => f(ma(g(b)))
+ }
+
+ // The definition about fails with:
+ // anon-type.scala:9: error: not found: value b
+ // def xmap[A, B](ma: Endo[A], f: A => B, g: B => A): Endo[B] = (b: B) => f(ma(g(b)))
+ // ^
+ // anon-type.scala:8: error: not found: type $anon
+ // implicit val EndoInvariantFunctor = new InvariantFunctor[Endo] {
+ // ^
+
+
+ // These both work:
+ // implicit val EndoInvariantFunctorAscribed: InvariantFunctor[Endo] = new InvariantFunctor[Endo] {
+ // def xmap[A, B](ma: Endo[A], f: A => B, g: B => A): Endo[B] = (b: B) => f(ma(g(b)))
+ // }
+ //
+ // implicit val EndoInvariantFunctorStubbed = new InvariantFunctor[Endo] {
+ // def xmap[A, B](ma: Endo[A], f: A => B, g: B => A): Endo[B] = error("stub")
+ // }
+}
+
+trait Endo[X]
+
+object Endo {
+ implicit def EndoTo[A](f: A => A): Endo[A] = new Endo[A] {
+ def apply(a: A) = f(a)
+ }
+
+ implicit def EndoFrom[A](e: Endo[A]): A => A = e.apply(_)
+} \ No newline at end of file
diff --git a/test/files/pos/t3373.scala b/test/files/pos/t3373.scala
new file mode 100644
index 0000000000..b4af3610bb
--- /dev/null
+++ b/test/files/pos/t3373.scala
@@ -0,0 +1,11 @@
+class Entry(time: Long) {
+ def getTime: Long = time
+}
+
+object Test {
+ def extractTime(e: Entry) = e.getTime
+
+ implicit val orderEntries = new Ordering[Entry] {
+ def compare(first: Entry, second: Entry) = extractTime(first) compare extractTime(second)
+ }
+} \ No newline at end of file