Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class SymUtils:
}

/** All traits implemented by a class, except for those inherited through the superclass.
* The empty list if `self` is a trait.
*/
* The empty list if `self` is a trait.
*/
def mixins(using Context): List[ClassSymbol] =
if (self.is(Trait)) Nil
else directlyInheritedTraits
Expand Down
5 changes: 2 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,10 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
yield transformFollowing(DefDef(mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span)))

def mixinForwarders(mixin: ClassSymbol): List[Tree] =
for (meth <- mixin.info.decls.toList if needsMixinForwarder(meth))
yield {
for meth <- mixin.info.decls.filter(needsMixinForwarder)
yield
util.Stats.record("mixin forwarders")
transformFollowing(DefDef(mkMixinForwarderSym(meth.asTerm), forwarderRhsFn(meth)))
}

def mkMixinForwarderSym(target: TermSymbol): TermSymbol =
val sym = mkForwarderSym(target, extraFlags = MixedIn)
Expand Down
20 changes: 13 additions & 7 deletions compiler/src/dotty/tools/dotc/transform/MixinOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package dotty.tools.dotc
package transform

import core.*
import Symbols.*, Types.*, Contexts.*, DenotTransformers.*, Flags.*
import Decorators.*, Symbols.*, Types.*, Contexts.*, DenotTransformers.*, Flags.*
import NameKinds.*
import util.Spans.*
import util.chaining.*

import StdNames.*, NameOps.*
import typer.Nullables
Expand All @@ -19,15 +20,20 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
map(n => getClassIfDefined("org.junit." + n)).
filter(_.exists)

def mkForwarderSym(member: TermSymbol, extraFlags: FlagSet = EmptyFlags): TermSymbol = {
val res = member.copy(
def mkForwarderSym(member: TermSymbol, extraFlags: FlagSet = EmptyFlags): TermSymbol =
member.copy(
owner = cls,
name = member.name.stripScala2LocalSuffix,
flags = member.flags &~ Deferred &~ Module | Synthetic | extraFlags,
info = cls.thisType.memberInfo(member)).enteredAfter(thisPhase).asTerm
res.addAnnotations(member.annotations.filter(_.symbol != defn.TailrecAnnot))
res
}
info = cls.thisType.memberInfo(member)
)
.enteredAfter(thisPhase)
.asTerm.tap: res =>
res.addAnnotations(member.annotations.filter(_.symbol != defn.TailrecAnnot))
res.setParamss(res.paramSymss)
atPhaseBeforeTransforms:
for (src, dst) <- member.paramSymss.flatten.filter(!_.isType).zip(res.paramSymss.flatten) do
dst.addAnnotations(src.annotations)

def superRef(target: Symbol, span: Span = cls.span): Tree = {
val sup = if (target.isConstructor && !target.owner.is(Trait))
Expand Down
10 changes: 10 additions & 0 deletions tests/run/i22991/Bar.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Blah extends scala.annotation.StaticAnnotation

trait Barly {
def bar[T](a: String, @Foo v: Int)(@Foo b: T, @Blah w: Int) = ()
extension [T](s: String) def f[U](@Foo t: T, @Foo u: U) = ()
}

class Bar extends Barly {
def bar2(@Foo v: Int) = ()
}
5 changes: 5 additions & 0 deletions tests/run/i22991/Foo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface Foo {
}
34 changes: 34 additions & 0 deletions tests/run/i22991/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// scalajs: --skip
//Test java runtime reflection access to @Runtime annotations on method parameters.
@main def Test =
def check(actual: Int)(expect: Int)(msg: => String): Unit =
assert(actual == expect, s"$msg expected $expect but actually $actual")
locally:
// def bar[T](a: String, @Foo v: Int)(@Foo b: T, @Blah w: Int)
val method = classOf[Bar].getMethod("bar", classOf[String], classOf[Int], classOf[Object], classOf[Int])
val annots = method.getParameterAnnotations()
check(annots.length)(4)("param count")
check(annots(0).length)(0)("count at 0")
check(annots(1).length)(1)("count at 1")
assert(annots(1)(0).isInstanceOf[Foo], "expect Foo at 1")
check(annots(2).length)(1)("count at 2")
assert(annots(2)(0).isInstanceOf[Foo], "expect Foo at 2")
check(annots(3).length)(0)("count at 3")

locally:
// def bar2(@Foo v: Int)
val method = classOf[Bar].getMethod("bar2", classOf[Int])
val annots = method.getParameterAnnotations()
check(annots.length)(1)("param count")
assert(annots(0)(0).isInstanceOf[Foo], "expect Foo at 0")

locally:
// extension [T](s: String) def f[U](@Foo t: T, @Foo u: U) = ()
val method = classOf[Bar].getMethod("f", classOf[String], classOf[Object], classOf[Object])
val annots = method.getParameterAnnotations()
check(annots.length)(3)("param count")
check(annots(0).length)(0)("count at 0")
check(annots(1).length)(1)("count at 1")
check(annots(2).length)(1)("count at 2")
assert(annots(1)(0).isInstanceOf[Foo], "expect Foo at 1")
assert(annots(2)(0).isInstanceOf[Foo], "expect Foo at 2")
Loading