@@ -195,6 +195,7 @@ class Namer { typer: Typer =>
195195
196196 val TypedAhead : Property .Key [tpd.Tree ] = new Property .Key
197197 val ExpandedTree : Property .Key [untpd.Tree ] = new Property .Key
198+ val ExportForwarders : Property .Key [List [tpd.MemberDef ]] = new Property .Key
198199 val SymOfTree : Property .Key [Symbol ] = new Property .Key
199200 val Deriver : Property .Key [typer.Deriver ] = new Property .Key
200201
@@ -932,6 +933,120 @@ class Namer { typer: Typer =>
932933
933934 def init (): Context = index(params)
934935
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+
9351050 /** The type signature of a ClassDef with given symbol */
9361051 override def completeInCreationContext (denot : SymDenotation ): Unit = {
9371052 val parents = impl.parents
@@ -1074,6 +1189,7 @@ class Namer { typer: Typer =>
10741189 cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing
10751190 cls.setNoInitsFlags(parentsKind(parents), bodyKind(rest))
10761191 if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(StableRealizable )
1192+ processExports(localCtx)
10771193 }
10781194 }
10791195
0 commit comments