diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index e5231018126a..6eedc729c226 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -954,10 +954,6 @@ 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. @@ -965,7 +961,7 @@ object desugar { */ 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) @@ -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 = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index da56757fc755..107eb7eb0f57 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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 { diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index bf8140562684..b95f7a0cf5ee 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -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) } diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 8c03b5fc1dbd..bffd02060a2b 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -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