Skip to content

Commit 6c20b59

Browse files
committed
Eta expansion uses local owner for binders
Before, they kept their original owner (the eta expanded class), which caused an owner-structure mismatch in pickling. This resulted in spurious recompilation and asSeenFrom crashes. Changing the owner of the binders used for eta-expansion, weirdly revealed a problem with typing annotations, where, I assume, reuse of the class type params hid the missing logic for dealing with polymorphic annotation classes and the undetparams that arise of typing their instantiation.
1 parent 9d8f485 commit 6c20b59

File tree

6 files changed

+51
-20
lines changed

6 files changed

+51
-20
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,16 @@ abstract class Pickler extends SubComponent {
9696
private def isRootSym(sym: Symbol) =
9797
sym.name.toTermName == rootName && sym.owner == rootOwner
9898

99-
/** Returns usually symbol's owner, but picks classfile root instead
100-
* for existentially bound variables that have a non-local owner.
101-
* Question: Should this be done for refinement class symbols as well?
102-
*
103-
* Note: tree pickling also finds its way here; e.g. in scala/bug#7501 the pickling
104-
* of trees in annotation arguments considers the parameter symbol of a method
105-
* called in such a tree as "local". The condition `sym.isValueParameter` was
106-
* added to fix that bug, but there may be a better way.
107-
*/
99+
/** Usually `sym.owner`, except when `sym` is pickle-local, while `sym.owner` is not.
100+
*
101+
* In the latter case, the alternative owner is the pickle root,
102+
* or a non-class owner of root (so that term-owned parameters remain term-owned).
103+
*
104+
* Note: tree pickling also finds its way here; e.g. in scala/bug#7501 the pickling
105+
* of trees in annotation arguments considers the parameter symbol of a method
106+
* called in such a tree as "local". The condition `sym.isValueParameter` was
107+
* added to fix that bug, but there may be a better way.
108+
*/
108109
private def localizedOwner(sym: Symbol) =
109110
if (isLocalToPickle(sym) && !isRootSym(sym) && !isLocalToPickle(sym.owner))
110111
// don't use a class as the localized owner for type parameters that are not owned by a class: those are not instantiated by asSeenFrom

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3741,18 +3741,20 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
37413741
typedFun0
37423742
)
37433743
val treeInfo.Applied(typedFun @ Select(New(annTpt), _), _, _) = typedFunPart
3744-
val annType = annTpt.tpe
3745-
val isJava = annType != null && annType.typeSymbol.isJavaDefined
3744+
val annType = annTpt.tpe // for a polymorphic annotation class, this type will have unbound type params (see context.undetparams)
3745+
val annTypeSym = annType.typeSymbol
3746+
val isJava = annType != null && annTypeSym.isJavaDefined
37463747

37473748
finish(
37483749
if (typedFun.isErroneous || annType == null)
37493750
ErroneousAnnotation
3750-
else if (isJava || annType.typeSymbol.isNonBottomSubClass(ConstantAnnotationClass)) {
3751+
else if (isJava || annTypeSym.isNonBottomSubClass(ConstantAnnotationClass)) {
37513752
// Arguments of Java annotations and ConstantAnnotations are checked to be constants and
37523753
// stored in the `assocs` field of the resulting AnnotationInfo
37533754
if (argss.length > 1) {
37543755
reportAnnotationError(MultipleArgumentListForAnnotationError(ann))
37553756
} else {
3757+
// TODO: annType may have undetermined type params -- can we infer them?
37563758
val annScopeJava =
37573759
if (isJava) annType.decls.filter(sym => sym.isMethod && !sym.isConstructor && sym.isJavaDefined)
37583760
else EmptyScope // annScopeJava is only used if isJava
@@ -3801,11 +3803,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
38013803
val typedAnn: Tree = {
38023804
// local dummy fixes scala/bug#5544
38033805
val localTyper = newTyper(context.make(ann, context.owner.newLocalDummy(ann.pos)))
3804-
localTyper.typed(ann, mode, annType)
3806+
localTyper.typed(ann, mode, deriveTypeWithWildcards(context.undetparams)(annType))
38053807
}
38063808
def annInfo(t: Tree): AnnotationInfo = t match {
38073809
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
3808-
AnnotationInfo(annType, args, List()).setOriginal(typedAnn).setPos(t.pos)
3810+
// `tpt.tpe` is more precise than `annType`, since it incorporates the types of `args`
3811+
AnnotationInfo(tpt.tpe, args, List()).setOriginal(typedAnn).setPos(t.pos)
38093812

38103813
case Block(stats, expr) =>
38113814
context.warning(t.pos, "Usage of named or default arguments transformed this annotation\n"+
@@ -3823,7 +3826,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
38233826
reportAnnotationError(UnexpectedTreeAnnotationError(t, typedAnn))
38243827
}
38253828

3826-
if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2)
3829+
if (annTypeSym == DeprecatedAttr && argss.flatten.size < 2)
38273830
context.deprecationWarning(ann.pos, DeprecatedAttr, "@deprecated now takes two arguments; see the scaladoc.", "2.11.0")
38283831

38293832
if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) ErroneousAnnotation

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,7 @@ trait Types
19431943
// (this can happen only for erroneous programs).
19441944
}
19451945

1946+
// TODO should we pull this out to reduce memory footprint of ClassInfoType?
19461947
private object enterRefs extends TypeMap {
19471948
private var tparam: Symbol = _
19481949

@@ -2496,13 +2497,23 @@ trait Types
24962497
val tpars = initializedTypeParams
24972498
if (tpars.isEmpty) this
24982499
else {
2500+
// It's not clear which owner we should use (we don't know the context we're in),
2501+
// but pos/t10762 shows it can't be the class (`sym`) that owns the type params,
2502+
// as that will confuse ASF during separate compilation.
2503+
//
2504+
// During pickling, a pickle-local symbol (the type param) that has a non-pickle-local owner (the class),
2505+
// will get a new owner (the pickle root, a class) assigned to it by localizedOwner.
2506+
// This causes spurious recompilation, as well as confusion in ASF.
2507+
// Thus, use a pickle-local term symbol owner and avoid this whole owner-rejiggering.
2508+
val pickleLocalOwner = sym.newLocalDummy(sym.pos)
2509+
24992510
// Since we're going to lose the information denoted by the prefix when pulling the type params
25002511
// out for use as binders in the PolyType, we must eagerly rewrite their infos using relativize
25012512
// to preserve that knowledge.
2502-
val denotedTpars = cloneSymbolsAndModify(tpars, relativize)
2513+
val denotedLocallyOwnedTpars = cloneSymbolsAtOwnerAndModify(tpars, pickleLocalOwner, relativize)
25032514

25042515
// @PP: use typeConstructor! #3343, #4018, #4347.
2505-
PolyType(denotedTpars, TypeRef(pre, sym, denotedTpars map (_.typeConstructor)))
2516+
PolyType(denotedLocallyOwnedTpars, TypeRef(pre, sym, denotedLocallyOwnedTpars map (_.typeConstructor)))
25062517
}
25072518
}
25082519

test/files/neg/hk-typevar-unification.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
hk-typevar-unification.scala:16: error: inferred kinds of the type arguments ([_ <: B]Foo[_]) do not conform to the expected kinds of the type parameters (type F).
22
[_ <: B]Foo[_]'s type parameters do not match type F's expected parameters:
3-
type _ (in class Foo)'s bounds <: B are stricter than type _'s declared bounds >: Nothing <: Any
3+
type _'s bounds <: B are stricter than type _'s declared bounds >: Nothing <: Any
44
f(tcFoo)
55
^
66
hk-typevar-unification.scala:16: error: type mismatch;
@@ -10,8 +10,8 @@ hk-typevar-unification.scala:16: error: type mismatch;
1010
^
1111
hk-typevar-unification.scala:19: error: inferred kinds of the type arguments ([_ <: B]Foo[_]) do not conform to the expected kinds of the type parameters (type F).
1212
[_ <: B]Foo[_]'s type parameters do not match type F's expected parameters:
13-
type _ (in class Foo) is invariant, but type _ is declared covariant
14-
type _ (in class Foo)'s bounds <: B are stricter than type _'s declared bounds >: Nothing <: Any
13+
type _ is invariant, but type _ is declared covariant
14+
type _'s bounds <: B are stricter than type _'s declared bounds >: Nothing <: Any
1515
g(tcFoo)
1616
^
1717
hk-typevar-unification.scala:19: error: type mismatch;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import language.higherKinds
2+
3+
trait Tycon[A]
4+
trait MatcherFactory1X[TC1[_]]
5+
trait Matcher[T]{
6+
class X {
7+
def be = {
8+
def inferTycon[TC1[_]](other: MatcherFactory1X[TC1]): MatcherFactory1X[TC1] = ???
9+
inferTycon(??? : MatcherFactory1X[Tycon])
10+
}
11+
}
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test {
2+
val m: Matcher[_] = ???
3+
val tpinfer = (new m.X).be
4+
}

0 commit comments

Comments
 (0)