Skip to content

Fix bridge generation for object definitions #4435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2018
Merged
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
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ object Flags {
/** Either method or lazy */
final val MethodOrLazy = Method | Lazy

/** Either method or module */
final val MethodOrModule = Method | Module
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to define a new one for only one use?

Copy link
Contributor Author

@odersky odersky May 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's slightly more efficient that way. The | computation takes time, it's not just a simple bitwise |.


/** Either method or lazy or deferred */
final val MethodOrLazyOrDeferred = Method | Lazy | Deferred

Expand Down
9 changes: 7 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Signature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,16 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
* This is the case if all parameter names are _consistent_, i.e. they are either
* equal or on of them is tpnme.Uninstantiated.
*/
final def consistentParams(that: Signature): Boolean = {
final def consistentParams(that: Signature)(implicit ctx: Context): Boolean = {
@tailrec def loop(names1: List[TypeName], names2: List[TypeName]): Boolean =
if (names1.isEmpty) names2.isEmpty
else !names2.isEmpty && consistent(names1.head, names2.head) && loop(names1.tail, names2.tail)
loop(this.paramsSig, that.paramsSig)
if (ctx.erasedTypes && (this == NotAMethod) != (that == NotAMethod))
false // After erasure, we allow fields and parameterless methods with the same name.
// This is needed to allow both a module field and a bridge method for an abstract val.
// Test case is patmatch-classtag.scala
else
loop(this.paramsSig, that.paramsSig)
}

/** `that` signature, but keeping all corresponding parts of `this` signature. */
Expand Down
11 changes: 8 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Bridges.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Bridges(root: ClassSymbol)(implicit ctx: Context) {
* only in classes, never in traits.
*/
override def parents = Array(root.superClass)
override def exclude(sym: Symbol) = !sym.is(Method) || super.exclude(sym)
override def exclude(sym: Symbol) = !sym.is(MethodOrModule) || super.exclude(sym)
}

//val site = root.thisType
Expand Down Expand Up @@ -97,8 +97,13 @@ class Bridges(root: ClassSymbol)(implicit ctx: Context) {
toBeRemoved += other
}

bridges +=
DefDef(bridge, This(root).select(member).appliedToArgss(_)).withPos(bridge.pos)
def bridgeRhs(argss: List[List[Tree]]) = {
val ref = This(root).select(member)
if (member.info.isParameterless) ref // can happen if `member` is a module
else ref.appliedToArgss(argss)
}

bridges += DefDef(bridge, bridgeRhs(_).withPos(bridge.pos))
}

/** Add all necessary bridges to template statements `stats`, and remove at the same
Expand Down
45 changes: 45 additions & 0 deletions tests/run/patmatch-classtag.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import reflect.ClassTag
trait API {
type CaseDef

implicit val tagForCaseDef: ClassTag[CaseDef]

trait CaseDefCompanion {
def apply(x: String): CaseDef
def unapply(x: CaseDef): Option[String]
}
lazy val CaseDef: CaseDefCompanion
}

object dotc {
case class CaseDef(str: String)
}

object Impl extends API {
type CaseDef = dotc.CaseDef

val tagForCaseDef: ClassTag[dotc.CaseDef] = implicitly[ClassTag[dotc.CaseDef]]

object CaseDef extends CaseDefCompanion {
def apply(str: String): CaseDef = dotc.CaseDef(str)
def unapply(x: CaseDef): Option[String] = Some(x.str)
}
}

object Test extends App {
val api: API = Impl
import api._

val x: Any = CaseDef("123")

x match {
case cdef: CaseDef =>
val x: CaseDef = cdef
println(cdef)
}
x match {
case cdef @ CaseDef(s) =>
val x: CaseDef = cdef
println(s)
}
}