Inferred references to inaccessible types shouldn't be made explicit
Closed this issue · 2 comments
Unfortunately the following code compiles:
case class A() {
protected case class B()
val getB = B()
}
val a = A()
val b = a.getB
(Note, that it also compiles with private[A]
instead of protected
, but doesn't compile with private
. Also note that code like this occurs [2] in the Scala standard library. Also see [1].)
The strange thing here is that even though the type of b
can be inferred, it cannot be explicitly written out. That is, the following does not compile:
val b: a.B = a.getB
Now the problem is that some of our transformations might want to write that type out. For example, if we have f(a.getB)
, then ANF used to create a ValDef for a.getB
and write out the type. This was fixed with b0e40f4 by leaving the type of all ValDefs empty.
However, the problem is not that easy to fix in some other situations, where we can't simply omit the type:
- when
b
is part of the closure of some code that we want to compile separately, then the type ofb
appears as the type of a parameter of the wrapper method - when we are processing a lambda that originally didn't have its parameter's type specified, but we pull it into a ValDef where it cannot inferred anymore.
- probably also when ANF introduces a DefDef
There are some solution ideas that might work:
- We could use the singleton type of
b
. - We could improvise a construct like C++'s
decltype
[3], and use it onb
.
[1] https://issues.scala-lang.org/browse/SI-6794
[2] See scala.collection.generic.GenericCompanion.Coll
, which escapes when calling for example zipWithIndex
.
[3] http://stackoverflow.com/questions/29038214/why-scala-does-not-have-a-decltype
The best we can do wrt to types IMO is the following:
- for
Symbol
s: always dealias and widen their type; - for
Ident
s to stable symbols that are subtypes ofAnyRef
: singleton type; - for
Select
s of stable paths: path-dependent type; - for
ValDef
s:- for parameters, ascribe with
lhs.info
, no type inference in this case; - if
lhs.info =:= rhs.tpe.dealias.widen
, no need for ascription; - otherwise ascribe with
lhs.info
(upcast);
- for parameters, ascribe with
- in
ANF
:- substitute path-dependent types with singleton types when necessary;
- keep track of expected type when creating symbols (esp. for call arguments).
I'm not sure how to do these changes in ANF
, but I will think about it.