Skip to content

Fix expansion and unexpansion of mixin qualified names #15712

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 3 commits into from
Jul 21, 2022
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
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ object NameOps {

/** Revert the expanded name. */
def unexpandedName: N = likeSpacedN {
name.replace { case ExpandedName(_, unexp) => unexp }
name.replaceDeep {
case ExpandedName(_, unexp) => unexp
}
}

def errorName: N = likeSpacedN(name ++ nme.ERROR)
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,18 @@ object Names {

/** Apply rewrite rule given by `f` to some part of this name, skipping and rewrapping
* other decorators.
* Stops at derived names whose kind has `definesNewName = true`.
* Stops at DerivedNames with infos of kind QualifiedInfo.
* If `f` does not apply to any part, return name unchanged.
*/
def replace(f: PartialFunction[Name, Name]): ThisName

/** Same as replace, but does not stop at DerivedNames with infos of kind QualifiedInfo. */
def replaceDeep(f: PartialFunction[Name, Name]): ThisName =
replace(f.orElse {
case DerivedName(underlying, info: QualifiedInfo) =>
underlying.replaceDeep(f).derived(info)
})

/** If partial function `f` is defined for some part of this name, apply it
* in a Some, otherwise None.
* Stops at derived names whose kind has `definesNewName = true`.
Expand Down
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -486,11 +486,10 @@ object SymDenotations {
def qualify(n: SimpleName) =
val qn = kind(prefix.toTermName, if (filler.isEmpty) n else termName(filler + n))
if kind == FlatName && !encl.is(JavaDefined) then qn.compactified else qn
val fn = name replace {
case name: SimpleName => qualify(name)
case name @ AnyQualifiedName(_, _) => qualify(name.toSimpleName)
val fn = name.replaceDeep {
case n: SimpleName => qualify(n)
}
if (name.isTypeName) fn.toTypeName else fn.toTermName
if name.isTypeName then fn.toTypeName else fn.toTermName
}

/** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */
Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ object Mixin {
val description: String = "expand trait fields and trait initializers"

def traitSetterName(getter: TermSymbol)(using Context): TermName =
extension (name: Name) def qualifiedToSimple = name.replace {
case n @ AnyQualifiedName(_, _) => n.toSimpleName
}
getter.ensureNotPrivate.name
.qualifiedToSimple // TODO: Find out why TraitSetterNames can't be defined over QualifiedNames
.expandedName(getter.owner, TraitSetterName)
.asTermName.syntheticSetterName
}
Expand Down
3 changes: 3 additions & 0 deletions tests/run/i15702.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
10
20
200
29 changes: 29 additions & 0 deletions tests/run/i15702.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
abstract class A:
val n: Int
def foo(): Int = n

trait B:
val m: Int
def foo(): Int = m

trait M extends A with B:
val a: Int
override def foo(): Int = a + super.foo()

trait N extends A with B:
val b: Int
override def foo(): Int = b * super.foo()

class Inner:
println(N.super[A].foo())
println(N.super.foo())
println(foo())

object C extends A with M with N:
val a = 10
val b = 10
val m = 10
val n = 10
new Inner()

@main def Test = C