diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 9aa5a4e931f5..80630f3afa18 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -542,6 +542,9 @@ object Flags { /** Either method or lazy */ final val MethodOrLazy = Method | Lazy + /** Either method or module */ + final val MethodOrModule = Method | Module + /** Either method or lazy or deferred */ final val MethodOrLazyOrDeferred = Method | Lazy | Deferred diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index cc4dd6b27a53..b1bc760df57e 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -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. */ diff --git a/compiler/src/dotty/tools/dotc/transform/Bridges.scala b/compiler/src/dotty/tools/dotc/transform/Bridges.scala index 445dd2d58a65..100c3c6dbebe 100644 --- a/compiler/src/dotty/tools/dotc/transform/Bridges.scala +++ b/compiler/src/dotty/tools/dotc/transform/Bridges.scala @@ -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 @@ -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 diff --git a/tests/run/patmatch-classtag.scala b/tests/run/patmatch-classtag.scala new file mode 100644 index 000000000000..f1f6645175e0 --- /dev/null +++ b/tests/run/patmatch-classtag.scala @@ -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) + } +}