diff options
author | Nicolas Stucki <nicolas.stucki@gmail.com> | 2017-01-06 10:58:12 +0100 |
---|---|---|
committer | Nicolas Stucki <nicolas.stucki@gmail.com> | 2017-01-06 15:12:05 +0100 |
commit | 9f505a42a1c100eedab9748321a77d4bc345af61 (patch) | |
tree | a1d53549419e63f8dab3b596d0169b8c5bf57b8a /compiler | |
parent | 42eb864dc752254fc3b8b0428570fe94aa1dafc7 (diff) | |
download | dotty-9f505a42a1c100eedab9748321a77d4bc345af61.tar.gz dotty-9f505a42a1c100eedab9748321a77d4bc345af61.tar.bz2 dotty-9f505a42a1c100eedab9748321a77d4bc345af61.zip |
Fix #1877: Add forwarders for primitive/generic mixins.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/src/dotty/tools/dotc/transform/MixinOps.scala | 35 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala | 14 |
2 files changed, 43 insertions, 6 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index 6cebf7197..c39e72b45 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -48,11 +48,7 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: * - there are multiple traits defining method with same signature */ def needsForwarder(meth: Symbol): Boolean = { - lazy val competingMethods = cls.baseClasses.iterator - .filter(_ ne meth.owner) - .map(meth.overriddenSymbol) - .filter(_.exists) - .toList + lazy val competingMethods = competingMethodsIterator(meth).toList def needsDisambiguation = competingMethods.exists(x=> !(x is Deferred)) // multiple implementations are available def hasNonInterfaceDefinition = competingMethods.exists(!_.owner.is(Trait)) // there is a definition originating from class @@ -61,8 +57,37 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: (needsDisambiguation || hasNonInterfaceDefinition || meth.owner.is(Scala2x)) } + /** Get `sym` of the method that needs a forwarder + * Method needs a forwarder in those cases: + * - there is a trait that defines a primitive version of implemented polymorphic method. + * - there is a trait that defines a polymorphic version of implemented primitive method. + */ + def needsPrimitiveForwarderTo(meth: Symbol): Option[Symbol] = { + def hasPrimitiveMissMatch(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { + case (tp1: MethodicType, tp2: MethodicType) => + hasPrimitiveMissMatch(tp1.resultType, tp2.resultType) || + tp1.paramTypess.flatten.zip(tp1.paramTypess.flatten).exists(args => hasPrimitiveMissMatch(args._1, args._2)) + case _ => + tp1.typeSymbol.isPrimitiveValueClass ^ tp2.typeSymbol.isPrimitiveValueClass + } + + def needsPrimitiveForwarder(m: Symbol): Boolean = + m.owner != cls && !m.is(Deferred) && hasPrimitiveMissMatch(meth.info, m.info) + + if (!meth.is(Method | Deferred, butNot = PrivateOrAccessor) || meth.overriddenSymbol(cls).exists || needsForwarder(meth)) None + else competingMethodsIterator(meth).find(needsPrimitiveForwarder) + } + + final val PrivateOrAccessor = Private | Accessor final val PrivateOrAccessorOrDeferred = Private | Accessor | Deferred def forwarder(target: Symbol) = (targs: List[Type]) => (vrefss: List[List[Tree]]) => superRef(target).appliedToTypes(targs).appliedToArgss(vrefss) + + private def competingMethodsIterator(meth: Symbol): Iterator[Symbol] = { + cls.baseClasses.iterator + .filter(_ ne meth.owner) + .map(meth.overriddenSymbol) + .filter(_.exists) + } } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index e718a7e60..c4d8f5e33 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -38,6 +38,14 @@ import ResolveSuper._ * * <mods> def f[Ts](ps1)...(psN): U = super[M].f[Ts](ps1)...(psN) * + * 3.3 (done in `methodPrimitiveForwarders`) For every method that is declared both + * as generic with a primitive type and with a primitive type + * `<mods> def f[Ts](ps1)...(psN): U` in trait M` and + * `<mods> def f[Ts](ps1)...(psN): V = ...` in implemented in N` + * where U is a primitive and V a polymorphic type (or vice versa) needs: + * + * <mods> def f[Ts](ps1)...(psN): U = super[N].f[Ts](ps1)...(psN) + * * A method in M needs to be disambiguated if it is concrete, not overridden in C, * and if it overrides another concrete method. * @@ -65,7 +73,11 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th for (meth <- mixin.info.decls.toList if needsForwarder(meth)) yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) - val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin)) + def methodPrimitiveForwarders: List[Tree] = + for (meth <- mixins.flatMap(_.info.decls.flatMap(needsPrimitiveForwarderTo)).distinct) + yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) + + val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin)) ::: methodPrimitiveForwarders cpy.Template(impl)(body = overrides ::: impl.body) } |