Skip to content

Commit

Permalink
Change naming scheme for anonymous extensions
Browse files Browse the repository at this point in the history
They now start with `extension_` instead of `given_`.
  • Loading branch information
odersky committed Jan 7, 2020
1 parent 5de0d5d commit 36b475c
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 32 deletions.
47 changes: 21 additions & 26 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -954,18 +954,14 @@ object desugar {
else tree
}

/** Invent a name for an anonympus given of type or template `impl`. */
def inventGivenName(impl: Tree)(implicit ctx: Context): SimpleName =
s"given_${inventName(impl)}".toTermName.asSimpleName

/** The normalized name of `mdef`. This means
* 1. Check that the name does not redefine a Scala core class.
* If it does redefine, issue an error and return a mangled name instead of the original one.
* 2. If the name is missing (this can be the case for instance definitions), invent one instead.
*/
def normalizeName(mdef: MemberDef, impl: Tree)(implicit ctx: Context): Name = {
var name = mdef.name
if (name.isEmpty) name = name.likeSpaced(inventGivenName(impl))
if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName(impl))
if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
def kind = if (name.isTypeName) "class" else "object"
ctx.error(em"illegal redefinition of standard $kind $name", mdef.sourcePos)
Expand All @@ -974,27 +970,26 @@ object desugar {
name
}

/** Invent a name for an anonymous instance with template `impl`.
*/
private def inventName(impl: Tree)(implicit ctx: Context): String = impl match {
case impl: Template =>
if (impl.parents.isEmpty)
impl.body.find {
case dd: DefDef if dd.mods.is(Extension) => true
case _ => false
}
match {
case Some(DefDef(name, _, (vparam :: _) :: _, _, _)) =>
s"${name}_of_${inventTypeName(vparam.tpt)}"
case _ =>
ctx.error(i"anonymous instance must implement a type or have at least one extension method", impl.sourcePos)
nme.ERROR.toString
}
else
impl.parents.map(inventTypeName(_)).mkString("_")
case impl: Tree =>
inventTypeName(impl)
}
/** Invent a name for an anonympus given or extension of type or template `impl`. */
def inventGivenOrExtensionName(impl: Tree)(given ctx: Context): SimpleName =
val str = impl match
case impl: Template =>
if impl.parents.isEmpty then
impl.body.find {
case dd: DefDef if dd.mods.is(Extension) => true
case _ => false
}
match
case Some(DefDef(name, _, (vparam :: _) :: _, _, _)) =>
s"extension_${name}_${inventTypeName(vparam.tpt)}"
case _ =>
ctx.error(i"anonymous instance must implement a type or have at least one extension method", impl.sourcePos)
nme.ERROR.toString
else
impl.parents.map(inventTypeName(_)).mkString("given_", "_", "")
case impl: Tree =>
"given_" ++ inventTypeName(impl)
str.toTermName.asSimpleName

private class NameExtractor(followArgs: Boolean) extends UntypedTreeAccumulator[String] {
private def extractArgs(args: List[Tree])(implicit ctx: Context): String =
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,7 @@ class Typer extends Namer
var name = tree.name
if (name == nme.WILDCARD && tree.mods.is(Given)) {
val Typed(_, tpt): @unchecked = tree.body
name = desugar.inventGivenName(tpt)
name = desugar.inventGivenOrExtensionName(tpt)
}
if (name == nme.WILDCARD) body1
else {
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/contextual/extension-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ given listOps: AnyRef {
def [T](xs: List[T]) second = xs.tail.head
def [T](xs: List[T]) third: T = xs.tail.tail.head
}
given given_largest_of_List_T: AnyRef {
given extension_largest_List_T: AnyRef {
def [T](xs: List[T]) largest (given Ordering[T])(n: Int) =
xs.sorted.takeRight(n)
}
Expand Down
16 changes: 12 additions & 4 deletions docs/docs/reference/contextual/relationship-implicits.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,23 @@ The synthesized type names are formed from
Tuples are treated as transparent, i.e. a type `F[(X, Y)]` would get the synthesized name
`F_X_Y`. Directly implemented function types `A => B` are represented as `A_to_B`. Function types used as arguments to other type constructors are represented as `Function`.

Anonymous given instances that define extension methods
get their name from the name of the first extension method and the toplevel type
constructor of its first parameter. For example, the given instance
### Anonymous Collective Extensions

Anonymous collective extensions also get compiler synthesized names, which are formed from

- the prefix `extension_`
- the name of the first defined extension method
- the simple name of the first parameter type of this extension method
- the simple name(s) of the toplevel argument type constructors to this type.

For example, the extension
```scala
extension of [T] (xs: List[T]) with {
def second = ...
}
```
gets the synthesized name `given_second_of_List_T`.
gets the synthesized name `extension_second_List_T`.


### Given Clauses

Expand Down

0 comments on commit 36b475c

Please sign in to comment.