-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Drop function 22 limit #1758
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
Drop function 22 limit #1758
Changes from all commits
f7001a4
e7a0d03
3116142
b94e6ea
636608a
055f12f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import core.StdNames._ | |
import core.NameOps._ | ||
import core.Decorators._ | ||
import core.Constants._ | ||
import core.Definitions._ | ||
import typer.NoChecking | ||
import typer.ProtoTypes._ | ||
import typer.ErrorReporting._ | ||
|
@@ -36,9 +37,17 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => | |
|
||
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match { | ||
case ref: SymDenotation => | ||
def isCompacted(sym: Symbol) = | ||
sym.isAnonymousFunction && { | ||
sym.info(ctx.withPhase(ctx.phase.next)) match { | ||
case MethodType(nme.ALLARGS :: Nil, _) => true | ||
case _ => false | ||
} | ||
} | ||
|
||
assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}") | ||
if (ref.symbol eq defn.ObjectClass) { | ||
// Aftre erasure, all former Any members are now Object members | ||
// After erasure, all former Any members are now Object members | ||
val ClassInfo(pre, _, ps, decls, selfInfo) = ref.info | ||
val extendedScope = decls.cloneScope | ||
for (decl <- defn.AnyClass.classInfo.decls) | ||
|
@@ -59,7 +68,10 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => | |
val oldInfo = ref.info | ||
val newInfo = transformInfo(ref.symbol, oldInfo) | ||
val oldFlags = ref.flags | ||
val newFlags = ref.flags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading | ||
val newFlags = | ||
if (oldSymbol.is(Flags.TermParam) && isCompacted(oldSymbol.owner)) oldFlags &~ Flags.Param | ||
else oldFlags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading | ||
|
||
// TODO: define derivedSymDenotation? | ||
if ((oldSymbol eq newSymbol) && (oldOwner eq newOwner) && (oldInfo eq newInfo) && (oldFlags == newFlags)) ref | ||
else { | ||
|
@@ -331,8 +343,23 @@ object Erasure extends TypeTestsCasts{ | |
* e.m -> e.[]m if `m` is an array operation other than `clone`. | ||
*/ | ||
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { | ||
val sym = tree.symbol | ||
assert(sym.exists, tree.show) | ||
|
||
def mapOwner(sym: Symbol): Symbol = { | ||
val owner = sym.owner | ||
if ((owner eq defn.AnyClass) || (owner eq defn.AnyValClass)) { | ||
assert(sym.isConstructor, s"${sym.showLocated}") | ||
defn.ObjectClass | ||
} | ||
else if (defn.isUnimplementedFunctionClass(owner)) | ||
defn.FunctionXXLClass | ||
else | ||
owner | ||
} | ||
|
||
var sym = tree.symbol | ||
val owner = mapOwner(sym) | ||
if (owner ne sym.owner) sym = owner.info.decl(sym.name).symbol | ||
assert(sym.exists, owner) | ||
|
||
def select(qual: Tree, sym: Symbol): Tree = { | ||
val name = tree.typeOpt match { | ||
|
@@ -366,11 +393,7 @@ object Erasure extends TypeTestsCasts{ | |
def recur(qual: Tree): Tree = { | ||
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType | ||
val symIsPrimitive = sym.owner.isPrimitiveValueClass | ||
if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass)) { | ||
assert(sym.isConstructor, s"${sym.showLocated}") | ||
select(qual, defn.ObjectClass.info.decl(sym.name).symbol) | ||
} | ||
else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType) | ||
if (qualIsPrimitive && !symIsPrimitive || qual.tpe.widenDealias.isErasedValueType) | ||
recur(box(qual)) | ||
else if (!qualIsPrimitive && symIsPrimitive) | ||
recur(unbox(qual, sym.owner.typeRef)) | ||
|
@@ -423,6 +446,9 @@ object Erasure extends TypeTestsCasts{ | |
} | ||
} | ||
|
||
/** Besides normal typing, this method collects all arguments | ||
* to a compacted function into a single argument of array type. | ||
*/ | ||
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { | ||
val Apply(fun, args) = tree | ||
if (fun.symbol == defn.dummyApply) | ||
|
@@ -434,7 +460,13 @@ object Erasure extends TypeTestsCasts{ | |
fun1.tpe.widen match { | ||
case mt: MethodType => | ||
val outers = outer.args(fun.asInstanceOf[tpd.Tree]) // can't use fun1 here because its type is already erased | ||
val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr) | ||
var args0 = outers ::: args ++ protoArgs(pt) | ||
if (args0.length > MaxImplementedFunctionArity && mt.paramTypes.length == 1) { | ||
val bunchedArgs = untpd.JavaSeqLiteral(args0, TypeTree(defn.ObjectType)) | ||
.withType(defn.ArrayOf(defn.ObjectType)) | ||
args0 = bunchedArgs :: Nil | ||
} | ||
val args1 = args0.zipWithConserve(mt.paramTypes)(typedExpr) | ||
untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType | ||
case _ => | ||
throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}") | ||
|
@@ -470,18 +502,36 @@ object Erasure extends TypeTestsCasts{ | |
super.typedValDef(untpd.cpy.ValDef(vdef)( | ||
tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym) | ||
|
||
/** Besides normal typing, this function also compacts anonymous functions | ||
* with more than `MaxImplementedFunctionArity` parameters to ise a single | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* parameter of type `[]Object`. | ||
*/ | ||
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = { | ||
val restpe = | ||
if (sym.isConstructor) defn.UnitType | ||
else sym.info.resultType | ||
var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil | ||
var rhs1 = ddef.rhs match { | ||
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe)) | ||
case _ => ddef.rhs | ||
} | ||
if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) { | ||
val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType)) | ||
def selector(n: Int) = ref(bunchedParam) | ||
.select(defn.Array_apply) | ||
.appliedTo(Literal(Constant(n))) | ||
val paramDefs = vparamss1.head.zipWithIndex.map { | ||
case (paramDef, idx) => | ||
assignType(untpd.cpy.ValDef(paramDef)(rhs = selector(idx)), paramDef.symbol) | ||
} | ||
vparamss1 = (tpd.ValDef(bunchedParam) :: Nil) :: Nil | ||
rhs1 = untpd.Block(paramDefs, rhs1) | ||
} | ||
val ddef1 = untpd.cpy.DefDef(ddef)( | ||
tparams = Nil, | ||
vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil, | ||
vparamss = vparamss1, | ||
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)), | ||
rhs = ddef.rhs match { | ||
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe)) | ||
case _ => ddef.rhs | ||
}) | ||
rhs = rhs1) | ||
super.typedDefDef(ddef1, sym) | ||
} | ||
|
||
|
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we implement
isImplementedFunctionClass
instead to avoid the double negation?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just one occurrence, so probably not.