Skip to content

Fix problem with by name params in mixed in methods. #296

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
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
15 changes: 11 additions & 4 deletions src/dotty/tools/dotc/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ object TypeErasure {
* treated. `eraseInfo` maps them them to nullary method types, whereas `erasure` maps them
* to `Function0`.
*/
def eraseInfo(tp: Type)(implicit ctx: Context): Type = scalaErasureFn.eraseInfo(tp)(erasureCtx)
def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
scalaErasureFn.eraseInfo(tp, sym)(erasureCtx)

/** The erasure of a function result type. Differs from normal erasure in that
* Unit is kept instead of being mapped to BoxedUnit.
Expand All @@ -145,7 +146,7 @@ object TypeErasure {
if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
else if (sym.isAbstractType) TypeAlias(WildcardType)
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
else eraseInfo(tp)(erasureCtx) match {
else eraseInfo(tp, sym)(erasureCtx) match {
case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
defn.BoxedUnitClass.typeRef
case einfo =>
Expand Down Expand Up @@ -347,8 +348,14 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
else JavaArrayType(this(elemtp))
}

def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
case ExprType(rt) => MethodType(Nil, Nil, eraseResult(rt))
def eraseInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match {
case ExprType(rt) =>
if (sym is Param) apply(tp)
// Note that params with ExprTypes are eliminated by ElimByName,
// but potentially re-introduced by ResolveSuper, when we add
// forwarders to mixin methods.
// See doc comment for ElimByName for speculation how we could improve this.
else MethodType(Nil, Nil, eraseResult(rt))
case tp => erasure(tp)
}

Expand Down
13 changes: 12 additions & 1 deletion src/dotty/tools/dotc/transform/ElimByName.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import ast.Trees._
*
* => T ==> () => T
*
* Note that `=> T` types are not eliminated in MnethodTypes. This is done later at erasure.
* Note that `=> T` types are not eliminated in MethodTypes. This is done later at erasure.
* Terms are rewritten as follows:
*
* x ==> x.apply() if x is a parameter that had type => T
Expand All @@ -41,6 +41,17 @@ import ast.Trees._
* DummyApply: [T](() => T): T
*
* is a synthetic method defined in Definitions. Erasure will later strip these DummyApply wrappers.
*
* Note: This scheme to have inconsistent types between method types (whose formal types are still
* ExprTypes and parameter valdefs (which are now FunctionTypes) is not pretty. There are two
* other options which have been abandoned or not yet pursued.
*
* Option 1: Transform => T to () => T also in method and function types. The problem with this is
* that is that it rewuires to look at every type, and this forces too much, causing
* Cyclic Reference errors. Abandoned for this reason.
*
* Option 2: Merge ElimByName with erasure, or have it run immediately before. This has not been
* tried yet.
*/
class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
import ast.tpd._
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
}
}
case ref =>
ref.derivedSingleDenotation(ref.symbol, eraseInfo(ref.info))
ref.derivedSingleDenotation(ref.symbol, eraseInfo(ref.info, ref.symbol))
}

val eraser = new Erasure.Typer
Expand Down