@@ -195,6 +195,7 @@ class Namer { typer: Typer =>
195
195
196
196
val TypedAhead : Property .Key [tpd.Tree ] = new Property .Key
197
197
val ExpandedTree : Property .Key [untpd.Tree ] = new Property .Key
198
+ val ExportForwarders : Property .Key [List [tpd.MemberDef ]] = new Property .Key
198
199
val SymOfTree : Property .Key [Symbol ] = new Property .Key
199
200
val Deriver : Property .Key [typer.Deriver ] = new Property .Key
200
201
@@ -932,6 +933,120 @@ class Namer { typer: Typer =>
932
933
933
934
def init (): Context = index(params)
934
935
936
+ /** Add forwarders as required by the export statements in this class */
937
+ private def processExports (implicit ctx : Context ): Unit = {
938
+
939
+ /** A string indicating that no forwarders for this kind of symbol are emitted */
940
+ val SKIP = " (skip)"
941
+
942
+ /** The forwarders defined by export `exp`.
943
+ */
944
+ def exportForwarders (exp : Export ): List [tpd.MemberDef ] = {
945
+ val buf = new mutable.ListBuffer [tpd.MemberDef ]
946
+ val Export (_, expr, selectors) = exp
947
+ val path = typedAheadExpr(expr, AnySelectionProto )
948
+ checkLegalImportPath(path)
949
+
950
+ def whyNoForwarder (mbr : SingleDenotation ): String = {
951
+ val sym = mbr.symbol
952
+ if (sym.is(ImplicitOrImplied ) != exp.impliedOnly) s " is ${if (exp.impliedOnly) " not " else " " }implied "
953
+ else if (! sym.isAccessibleFrom(path.tpe)) " is not accessible"
954
+ else if (sym.isConstructor || sym.is(ModuleClass ) || sym.is(Bridge )) SKIP
955
+ else if (cls.derivesFrom(sym.owner) &&
956
+ (sym.owner == cls || ! sym.is(Deferred ))) i " is already a member of $cls"
957
+ else " "
958
+ }
959
+
960
+ /** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
961
+ * provided `mbr` is accessible and of the right implicit/non-implicit kind.
962
+ */
963
+ def addForwarder (alias : TermName , mbr : SingleDenotation , span : Span ): Unit = {
964
+ if (whyNoForwarder(mbr) == " " ) {
965
+
966
+ /** The info of a forwarder to type `ref` which has info `info`
967
+ */
968
+ def fwdInfo (ref : Type , info : Type ): Type = info match {
969
+ case _ : ClassInfo =>
970
+ HKTypeLambda .fromParams(info.typeParams, ref)
971
+ case _ : TypeBounds =>
972
+ TypeAlias (ref)
973
+ case info : HKTypeLambda =>
974
+ info.derivedLambdaType(info.paramNames, info.paramInfos,
975
+ fwdInfo(ref.appliedTo(info.paramRefs), info.resultType))
976
+ case info => // should happen only in error cases
977
+ info
978
+ }
979
+
980
+ val forwarder =
981
+ if (mbr.isType)
982
+ ctx.newSymbol(
983
+ cls, alias.toTypeName,
984
+ Final ,
985
+ fwdInfo(path.tpe.select(mbr.symbol), mbr.info),
986
+ coord = span)
987
+ else {
988
+ val maybeStable = if (mbr.symbol.isStableMember) StableRealizable else EmptyFlags
989
+ ctx.newSymbol(
990
+ cls, alias,
991
+ Method | Final | maybeStable | mbr.symbol.flags & ImplicitOrImplied ,
992
+ mbr.info.ensureMethodic,
993
+ coord = span)
994
+ }
995
+ val forwarderDef =
996
+ if (forwarder.isType) tpd.TypeDef (forwarder.asType)
997
+ else {
998
+ import tpd ._
999
+ val ref = path.select(mbr.symbol.asTerm)
1000
+ tpd.polyDefDef(forwarder.asTerm, targs => prefss =>
1001
+ ref.appliedToTypes(targs).appliedToArgss(prefss)
1002
+ )
1003
+ }
1004
+ buf += forwarderDef.withSpan(span)
1005
+ }
1006
+ }
1007
+
1008
+ def addForwardersNamed (name : TermName , alias : TermName , span : Span ): Unit = {
1009
+ val size = buf.size
1010
+ val mbrs = List (name, name.toTypeName).flatMap(path.tpe.member(_).alternatives)
1011
+ mbrs.foreach(addForwarder(alias, _, span))
1012
+ if (buf.size == size) {
1013
+ val reason = mbrs.map(whyNoForwarder).dropWhile(_ == SKIP ) match {
1014
+ case Nil => " "
1015
+ case why :: _ => i " \n $path. $name cannot be exported because it $why"
1016
+ }
1017
+ ctx.error(i """ no eligible member $name at $path$reason""" , ctx.source.atSpan(span))
1018
+ }
1019
+ }
1020
+
1021
+ def addForwardersExcept (seen : List [TermName ], span : Span ): Unit =
1022
+ for (mbr <- path.tpe.allMembers) {
1023
+ val alias = mbr.name.toTermName
1024
+ if (! seen.contains(alias)) addForwarder(alias, mbr, span)
1025
+ }
1026
+
1027
+ def recur (seen : List [TermName ], sels : List [untpd.Tree ]): Unit = sels match {
1028
+ case (sel @ Ident (nme.WILDCARD )) :: _ =>
1029
+ addForwardersExcept(seen, sel.span)
1030
+ case (sel @ Ident (name : TermName )) :: rest =>
1031
+ addForwardersNamed(name, name, sel.span)
1032
+ recur(name :: seen, rest)
1033
+ case Thicket ((sel @ Ident (fromName : TermName )) :: Ident (toName : TermName ) :: Nil ) :: rest =>
1034
+ if (toName != nme.WILDCARD ) addForwardersNamed(fromName, toName, sel.span)
1035
+ recur(fromName :: seen, rest)
1036
+ case _ =>
1037
+ }
1038
+
1039
+ recur(Nil , selectors)
1040
+ val forwarders = buf.toList
1041
+ exp.pushAttachment(ExportForwarders , forwarders)
1042
+ forwarders
1043
+ }
1044
+
1045
+ val forwarderss =
1046
+ for (exp @ Export (_, _, _) <- rest) yield exportForwarders(exp)
1047
+ forwarderss.foreach(_.foreach(fwdr => fwdr.symbol.entered))
1048
+ }
1049
+
935
1050
/** The type signature of a ClassDef with given symbol */
936
1051
override def completeInCreationContext (denot : SymDenotation ): Unit = {
937
1052
val parents = impl.parents
@@ -1074,6 +1189,7 @@ class Namer { typer: Typer =>
1074
1189
cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing
1075
1190
cls.setNoInitsFlags(parentsKind(parents), bodyKind(rest))
1076
1191
if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(StableRealizable )
1192
+ processExports(localCtx)
1077
1193
}
1078
1194
}
1079
1195
0 commit comments