Skip to content

Commit

Permalink
Simplify and fix type forwarders
Browse files Browse the repository at this point in the history
The previous scheme did not work correctly for forwarding classes.
the previous commit fixed that for unparameterized classes, but
parameterized classes still had a problem, The current scheme
is far simpler since it always uses unparameterized aliases.
  • Loading branch information
odersky committed Sep 26, 2019
1 parent 3d3021c commit 80880d5
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 21 deletions.
32 changes: 11 additions & 21 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ast._
import Trees._, StdNames._, Scopes._, Denotations._, Comments._
import Contexts._, Symbols._, Types._, SymDenotations._, Names._, NameOps._, Flags._, Decorators._
import NameKinds.DefaultGetterName
import TypeApplications.TypeParamInfo
import ast.desugar, ast.desugar._
import ProtoTypes._
import util.Spans._
Expand Down Expand Up @@ -977,44 +978,33 @@ class Namer { typer: Typer =>
*/
def addForwarder(alias: TermName, mbr: SingleDenotation, span: Span): Unit =
if (whyNoForwarder(mbr) == "") {

/** The info of a forwarder to type `ref` which has info `info`
*/
def fwdInfo(ref: Type, info: Type): Type = info match {
case _: ClassInfo =>
if (info.typeParams.isEmpty) TypeAlias(ref)
else HKTypeLambda.fromParams(info.typeParams, ref)
case _: TypeBounds =>
TypeAlias(ref)
case info: HKTypeLambda =>
info.derivedLambdaType(info.paramNames, info.paramInfos,
fwdInfo(ref.appliedTo(info.paramRefs), info.resultType))
case info => // should happen only in error cases
info
}

val sym = mbr.symbol
val forwarder =
if (mbr.isType)
ctx.newSymbol(
cls, alias.toTypeName,
Exported | Final,
fwdInfo(path.tpe.select(mbr.symbol), mbr.info),
TypeAlias(path.tpe.select(sym)),
coord = span)
// Note: This will always create unparameterzied aliases. So even if the original type is
// a parameterized class, say `C[X]` the alias will read `type C = d.C`. We currently do
// allow such type aliases. If we forbid them at some point (requiring the referred type to be
// fully applied), we'd have to change the scheme here as well.
else {
val (maybeStable, mbrInfo) =
if (mbr.symbol.isStableMember && mbr.symbol.isPublic)
(StableRealizable, ExprType(path.tpe.select(mbr.symbol)))
if (sym.isStableMember && sym.isPublic)
(StableRealizable, ExprType(path.tpe.select(sym)))
else
(EmptyFlags, mbr.info.ensureMethodic)
val mbrFlags = Exported | Method | Final | maybeStable | mbr.symbol.flags & RetainedExportFlags
val mbrFlags = Exported | Method | Final | maybeStable | sym.flags & RetainedExportFlags
ctx.newSymbol(cls, alias, mbrFlags, mbrInfo, coord = span)
}
forwarder.info = avoidPrivateLeaks(forwarder)
val forwarderDef =
if (forwarder.isType) tpd.TypeDef(forwarder.asType)
else {
import tpd._
val ref = path.select(mbr.symbol.asTerm)
val ref = path.select(sym.asTerm)
tpd.polyDefDef(forwarder.asTerm, targs => prefss =>
ref.appliedToTypes(targs).appliedToArgss(prefss)
)
Expand Down
27 changes: 27 additions & 0 deletions tests/pos/i7219.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,30 @@ class Foo {
val a: MyEnum.Blue = ???
a : Blue // ok
}

object Test {
object Types {
type T <: AnyRef
type U = T
type TC[X] <: AnyRef
type UC[X] = TC[(X, X)]
class C
class D[X] extends C
def x1: T = ???
def x2: U = ???
def x3: TC[Int] = ???
def x4: UC[Int] = ???
def x5: C = C()
def x6: D[Int] = D()
}
export Types._
type D1 = Types.D
type U1 = Types.UC

val y1: T = x1
val y2: U = x2
val y3: TC[Int] = x3
val y4: UC[Int] = x4
val y5: C = x5
val y6: D[Int] = x6
}

0 comments on commit 80880d5

Please sign in to comment.