-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Adapt type parameters of typed eta expansion according to expected variances #950
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
Changes from all commits
d53da95
199dca7
7a61c86
c435a8a
e5fcf57
17a5066
b37b9e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,8 +112,6 @@ object Scala2Unpickler { | |
if (tsym.exists) tsym.setFlag(TypeParam) | ||
else denot.enter(tparam, decls) | ||
} | ||
denot.info = ClassInfo( | ||
denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost) // more refined infowith parents | ||
if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls) | ||
|
||
val scalacCompanion = denot.classSymbol.scalacLinkedClass | ||
|
@@ -151,6 +149,51 @@ object Scala2Unpickler { | |
denot.info = ClassInfo( // final info | ||
denot.owner.thisType, denot.classSymbol, parentRefs, declsInRightOrder, ost) | ||
} | ||
|
||
/** Adapt arguments to type parameters so that variance of type lambda arguments | ||
* agrees with variance of corresponding higherkinded type parameters. Example: | ||
* | ||
* class Companion[+CC[X]] | ||
* Companion[List] | ||
* | ||
* with adaptArgs, this will expand to | ||
* | ||
* Companion[[X] => List[X]] | ||
* | ||
* instead of | ||
* | ||
* Companion[[+X] => List[X]] | ||
* | ||
* even though `List` is covariant. This adaptation is necessary to ignore conflicting | ||
* variances in overriding members that have types of hk-type parameters such as `Companion[GenTraversable]` | ||
* or `Companion[ListBuffer]`. Without the adaptation we would end up with | ||
* | ||
* Companion[[+X] => GenTraversable[X]] | ||
* Companion[[X] => List[X]] | ||
* | ||
* and the second is not a subtype of the first. So if we have overridding memebrs of the two | ||
* types we get an error. | ||
*/ | ||
def adaptArgs(tparams: List[Symbol], args: List[Type])(implicit ctx: Context): List[Type] = tparams match { | ||
case tparam :: tparams1 => | ||
val boundLambda = tparam.infoOrCompleter match { | ||
case TypeBounds(_, hi) => hi.LambdaClass(forcing = false) | ||
case _ => NoSymbol | ||
} | ||
def adaptArg(arg: Type): Type = arg match { | ||
case arg: TypeRef if arg.symbol.isLambdaTrait => | ||
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. Unrelated to this change, but the definition of
Looks prone to falsely matching:
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. Right, we should restrict this to members of the scala package. |
||
assert(arg.symbol.typeParams.length == boundLambda.typeParams.length) | ||
arg.prefix.select(boundLambda) | ||
case arg: RefinedType => | ||
arg.derivedRefinedType(adaptArg(arg.parent), arg.refinedName, arg.refinedInfo) | ||
case _ => | ||
arg | ||
} | ||
val arg = args.head | ||
val adapted = if (boundLambda.exists) adaptArg(arg) else arg | ||
adapted :: adaptArgs(tparams1, args.tail) | ||
case nil => args | ||
} | ||
} | ||
|
||
/** Unpickle symbol table information descending from a class and/or module root | ||
|
@@ -723,8 +766,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas | |
else TypeRef(pre, sym.name.asTypeName) | ||
val args = until(end, readTypeRef) | ||
if (sym == defn.ByNameParamClass2x) ExprType(args.head) | ||
else if (args.isEmpty && sym.typeParams.nonEmpty) tycon.EtaExpand | ||
else tycon.appliedTo(args) | ||
else if (args.isEmpty && sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams) | ||
else tycon.appliedTo(adaptArgs(sym.typeParams, args)) | ||
case TYPEBOUNDStpe => | ||
TypeBounds(readTypeRef(), readTypeRef()) | ||
case REFINEDtpe => | ||
|
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.
I'm assuming that the "otherwise" case here only reached in ill-typed programs, and will result in an error being issued in
adapt
. Is that assumption right?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.
I think it can also appear in tryLifted, which gets called during a subtype check. Essentially, we compare an unexpanded hk type with a type lambda and go on expanding the unexpanded type. It seems we can get a discrepancy in variances there.