From 290a9ff63bba43fa3ad5dae3214dad7f4c3c19e7 Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 14 Dec 2022 17:48:03 +0100 Subject: [PATCH 1/3] Support inline overrides in value classes Fixes #15725 Three fixes: - Don't make extension method copies of inline methods - Make retainedBody methods discoverable by entering them in their parent scope, so that they get an extension methos - But strip the retainedBody in the extension method --- compiler/src/dotty/tools/dotc/inlines/Inlines.scala | 2 +- .../dotty/tools/dotc/transform/ExtensionMethods.scala | 9 ++++++--- .../src/dotty/tools/dotc/transform/ValueClasses.scala | 1 + tests/run/i15725.check | 1 + tests/run/i15725.scala | 8 ++++++++ 5 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/run/i15725.check create mode 100644 tests/run/i15725.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index ff08d551ca87..95cbea9fa3b5 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -230,7 +230,7 @@ object Inlines: val retainer = meth.copy( name = BodyRetainerName(meth.name), flags = meth.flags &~ (Inline | Macro | Override) | Private, - coord = mdef.rhs.span.startPos).asTerm + coord = mdef.rhs.span.startPos).asTerm.entered retainer.deriveTargetNameAnnotation(meth, name => BodyRetainerName(name.asTermName)) DefDef(retainer, prefss => inlineCall( diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 7c76211ca8ec..a430f7532066 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -13,7 +13,7 @@ import core._ import Types._, Contexts._, Names._, Flags._, DenotTransformers._, Phases._ import SymDenotations._, Symbols._, StdNames._, Denotations._ import TypeErasure.{ valueErasure, ErasedValueType } -import NameKinds.ExtMethName +import NameKinds.{ExtMethName, BodyRetainerName} import Decorators._ import TypeUtils._ @@ -79,7 +79,7 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete // because it adds extension methods before pickling. if (!(valueClass.is(Scala2x))) for (decl <- valueClass.classInfo.decls) - if (isMethodWithExtension(decl)) + if isMethodWithExtension(decl) then enterInModuleClass(createExtensionMethod(decl, moduleClassSym.symbol)) // Create synthetic methods to cast values between the underlying type @@ -179,7 +179,10 @@ object ExtensionMethods { /** Name of the extension method that corresponds to given instance method `meth`. */ def extensionName(imeth: Symbol)(using Context): TermName = - ExtMethName(imeth.name.asTermName) + ExtMethName( + imeth.name.asTermName match + case BodyRetainerName(name) => name + case name => name) /** Return the extension method that corresponds to given instance method `meth`. */ def extensionMethod(imeth: Symbol)(using Context): TermSymbol = diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index a86bf2c48fb5..92cbd0e57ac5 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -29,6 +29,7 @@ object ValueClasses { isDerivedValueClass(d.owner) && !d.isConstructor && !d.symbol.isSuperAccessor && + !d.isInlineMethod && !d.is(Macro) } diff --git a/tests/run/i15725.check b/tests/run/i15725.check new file mode 100644 index 000000000000..60162b2f2fb4 --- /dev/null +++ b/tests/run/i15725.check @@ -0,0 +1 @@ +2.0 meters diff --git a/tests/run/i15725.scala b/tests/run/i15725.scala new file mode 100644 index 000000000000..d3b735f6314c --- /dev/null +++ b/tests/run/i15725.scala @@ -0,0 +1,8 @@ +class ToString(d:Double) extends AnyVal : + inline override def toString():String = s"$d meters" + +@main def Test = + val ts = ToString(2.0) + val a: Any = ts + println(a) + From 063adfe586b6101a0dc278dc9c8e67383cda5eb1 Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 14 Dec 2022 18:47:20 +0100 Subject: [PATCH 2/3] Drop AbsOverride flag in bodyRetainer methods This was not noticed before since bodyRetainers were not entered in scope, so were not subject to override checking. --- compiler/src/dotty/tools/dotc/inlines/Inlines.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 95cbea9fa3b5..8110fd2de195 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -229,7 +229,7 @@ object Inlines: val retainer = meth.copy( name = BodyRetainerName(meth.name), - flags = meth.flags &~ (Inline | Macro | Override) | Private, + flags = (meth.flags &~ (Inline | Macro | Override | AbsOverride)) | Private, coord = mdef.rhs.span.startPos).asTerm.entered retainer.deriveTargetNameAnnotation(meth, name => BodyRetainerName(name.asTermName)) DefDef(retainer, prefss => From ac100532b2fb3cff12d12dd33148a025d9673bea Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 14 Dec 2022 19:26:47 +0100 Subject: [PATCH 3/3] Make Test ScalaJS friendly Doubles print differently on ScalaJS, use Ints instead. --- tests/run/i15725.check | 2 +- tests/run/i15725.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run/i15725.check b/tests/run/i15725.check index 60162b2f2fb4..f4de0404545d 100644 --- a/tests/run/i15725.check +++ b/tests/run/i15725.check @@ -1 +1 @@ -2.0 meters +2 meters diff --git a/tests/run/i15725.scala b/tests/run/i15725.scala index d3b735f6314c..e285d87bb456 100644 --- a/tests/run/i15725.scala +++ b/tests/run/i15725.scala @@ -1,8 +1,8 @@ -class ToString(d:Double) extends AnyVal : +class ToString(d: Int) extends AnyVal : inline override def toString():String = s"$d meters" @main def Test = - val ts = ToString(2.0) + val ts = ToString(2) val a: Any = ts println(a)