@@ -972,162 +972,171 @@ class Namer { typer: Typer =>
972972
973973 def init (): Context = index(params)
974974
975- /** Add forwarders as required by the export statements in this class */
976- private def processExports (using Context ): Unit = {
975+ /** The forwarders defined by export `exp` */
976+ def exportForwarders (exp : Export )(using Context ): List [tpd.MemberDef ] =
977+ val SKIP = " (skip)" // A string indicating that no forwarders for this kind of symbol are emitted
978+ val buf = new mutable.ListBuffer [tpd.MemberDef ]
979+ val Export (expr, selectors) = exp
980+ if expr.isEmpty then
981+ report.error(em " Export selector must have prefix and `.` " , exp.srcPos)
982+ return Nil
983+
984+ val path = typedAheadExpr(expr, AnySelectionProto )
985+ checkLegalExportPath(path, selectors)
986+ lazy val wildcardBound = importBound(selectors, isGiven = false )
987+ lazy val givenBound = importBound(selectors, isGiven = true )
988+
989+ def whyNoForwarder (mbr : SingleDenotation ): String = {
990+ val sym = mbr.symbol
991+ if (! sym.isAccessibleFrom(path.tpe)) " is not accessible"
992+ else if (sym.isConstructor || sym.is(ModuleClass ) || sym.is(Bridge ) || sym.is(ConstructorProxy )) SKIP
993+ else if (cls.derivesFrom(sym.owner) &&
994+ (sym.owner == cls || ! sym.is(Deferred ))) i " is already a member of $cls"
995+ else if (sym.is(Override ))
996+ sym.allOverriddenSymbols.find(
997+ other => cls.derivesFrom(other.owner) && ! other.is(Deferred )) match {
998+ case Some (other) => i " overrides ${other.showLocated}, which is already a member of $cls"
999+ case None => " "
1000+ }
1001+ else " "
1002+ }
9771003
978- /** A string indicating that no forwarders for this kind of symbol are emitted */
979- val SKIP = " (skip)"
1004+ /** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
1005+ * provided `mbr` is accessible and of the right implicit/non-implicit kind.
1006+ */
1007+ def addForwarder (alias : TermName , mbr : SingleDenotation , span : Span ): Unit =
1008+
1009+ def adaptForwarderParams (acc : List [List [tpd.Tree ]], tp : Type , prefss : List [List [tpd.Tree ]])
1010+ : List [List [tpd.Tree ]] = tp match
1011+ case mt : MethodType
1012+ if mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam =>
1013+ // Note: in this branch we use the assumptions
1014+ // that `prefss.head` corresponds to `mt.paramInfos` and
1015+ // that `prefss.tail` corresponds to `mt.resType`
1016+ val init :+ vararg = prefss.head
1017+ val prefs = init :+ ctx.typeAssigner.seqToRepeated(vararg)
1018+ adaptForwarderParams(prefs :: acc, mt.resType, prefss.tail)
1019+ case mt : MethodOrPoly =>
1020+ adaptForwarderParams(prefss.head :: acc, mt.resultType, prefss.tail)
1021+ case _ =>
1022+ acc.reverse ::: prefss
9801023
981- /** The forwarders defined by export `exp`.
982- */
983- def exportForwarders (exp : Export ): List [tpd.MemberDef ] = {
984- val buf = new mutable.ListBuffer [tpd.MemberDef ]
985- val Export (expr, selectors) = exp
986- if expr.isEmpty then
987- report.error(em " Export selector must have prefix and `.` " , exp.srcPos)
988- return Nil
989-
990- val path = typedAheadExpr(expr, AnySelectionProto )
991- checkLegalExportPath(path, selectors)
992- lazy val wildcardBound = importBound(selectors, isGiven = false )
993- lazy val givenBound = importBound(selectors, isGiven = true )
994-
995- def whyNoForwarder (mbr : SingleDenotation ): String = {
1024+ if whyNoForwarder(mbr) == " " then
9961025 val sym = mbr.symbol
997- if (! sym.isAccessibleFrom(path.tpe)) " is not accessible"
998- else if (sym.isConstructor || sym.is(ModuleClass ) || sym.is(Bridge ) || sym.is(ConstructorProxy )) SKIP
999- else if (cls.derivesFrom(sym.owner) &&
1000- (sym.owner == cls || ! sym.is(Deferred ))) i " is already a member of $cls"
1001- else if (sym.is(Override ))
1002- sym.allOverriddenSymbols.find(
1003- other => cls.derivesFrom(other.owner) && ! other.is(Deferred )) match {
1004- case Some (other) => i " overrides ${other.showLocated}, which is already a member of $cls"
1005- case None => " "
1026+ val forwarder =
1027+ if mbr.isType then
1028+ val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false , span)
1029+ var target = path.tpe.select(sym)
1030+ if target.typeParams.nonEmpty then
1031+ target = target.EtaExpand (target.typeParams)
1032+ newSymbol(
1033+ cls, forwarderName,
1034+ Exported | Final ,
1035+ TypeAlias (target),
1036+ coord = span)
1037+ // Note: This will always create unparameterzied aliases. So even if the original type is
1038+ // a parameterized class, say `C[X]` the alias will read `type C = d.C`. We currently do
1039+ // allow such type aliases. If we forbid them at some point (requiring the referred type to be
1040+ // fully applied), we'd have to change the scheme here as well.
1041+ else {
1042+ def refersToPrivate (tp : Type ): Boolean = tp match
1043+ case tp : TermRef => tp.termSymbol.is(Private ) || refersToPrivate(tp.prefix)
1044+ case _ => false
1045+ val (maybeStable, mbrInfo) =
1046+ if sym.isStableMember && sym.isPublic && ! refersToPrivate(path.tpe) then
1047+ (StableRealizable , ExprType (path.tpe.select(sym)))
1048+ else
1049+ (EmptyFlags , mbr.info.ensureMethodic)
1050+ var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & RetainedExportFlags
1051+ if sym.is(ExtensionMethod ) then mbrFlags |= ExtensionMethod
1052+ val forwarderName = checkNoConflict(alias, isPrivate = false , span)
1053+ newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span)
10061054 }
1007- else " "
1008- }
1009-
1010- /** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
1011- * provided `mbr` is accessible and of the right implicit/non-implicit kind.
1012- */
1013- def addForwarder (alias : TermName , mbr : SingleDenotation , span : Span ): Unit =
1014-
1015- def adaptForwarderParams (acc : List [List [tpd.Tree ]], tp : Type , prefss : List [List [tpd.Tree ]])
1016- : List [List [tpd.Tree ]] = tp match
1017- case mt : MethodType
1018- if mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam =>
1019- // Note: in this branch we use the assumptions
1020- // that `prefss.head` corresponds to `mt.paramInfos` and
1021- // that `prefss.tail` corresponds to `mt.resType`
1022- val init :+ vararg = prefss.head
1023- val prefs = init :+ ctx.typeAssigner.seqToRepeated(vararg)
1024- adaptForwarderParams(prefs :: acc, mt.resType, prefss.tail)
1025- case mt : MethodOrPoly =>
1026- adaptForwarderParams(prefss.head :: acc, mt.resultType, prefss.tail)
1027- case _ =>
1028- acc.reverse ::: prefss
1029-
1030- if whyNoForwarder(mbr) == " " then
1031- val sym = mbr.symbol
1032- val forwarder =
1033- if mbr.isType then
1034- val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false , span)
1035- var target = path.tpe.select(sym)
1036- if target.typeParams.nonEmpty then
1037- target = target.EtaExpand (target.typeParams)
1038- newSymbol(
1039- cls, forwarderName,
1040- Exported | Final ,
1041- TypeAlias (target),
1042- coord = span)
1043- // Note: This will always create unparameterzied aliases. So even if the original type is
1044- // a parameterized class, say `C[X]` the alias will read `type C = d.C`. We currently do
1045- // allow such type aliases. If we forbid them at some point (requiring the referred type to be
1046- // fully applied), we'd have to change the scheme here as well.
1047- else {
1048- def refersToPrivate (tp : Type ): Boolean = tp match
1049- case tp : TermRef => tp.termSymbol.is(Private ) || refersToPrivate(tp.prefix)
1050- case _ => false
1051- val (maybeStable, mbrInfo) =
1052- if sym.isStableMember && sym.isPublic && ! refersToPrivate(path.tpe) then
1053- (StableRealizable , ExprType (path.tpe.select(sym)))
1054- else
1055- (EmptyFlags , mbr.info.ensureMethodic)
1056- var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & RetainedExportFlags
1057- if sym.is(ExtensionMethod ) then mbrFlags |= ExtensionMethod
1058- val forwarderName = checkNoConflict(alias, isPrivate = false , span)
1059- newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span)
1060- }
1061- forwarder.info = avoidPrivateLeaks(forwarder)
1062- forwarder.addAnnotations(sym.annotations)
1063- val forwarderDef =
1064- if (forwarder.isType) tpd.TypeDef (forwarder.asType)
1065- else {
1066- import tpd ._
1067- val ref = path.select(sym.asTerm)
1068- val ddef = tpd.DefDef (forwarder.asTerm, prefss =>
1069- ref.appliedToArgss(adaptForwarderParams(Nil , sym.info, prefss))
1070- )
1071- if forwarder.isInlineMethod then
1072- PrepareInlineable .registerInlineInfo(forwarder, ddef.rhs)
1073- ddef
1074- }
1075-
1076- buf += forwarderDef.withSpan(span)
1077- end addForwarder
1078-
1079- def addForwardersNamed (name : TermName , alias : TermName , span : Span ): Unit = {
1080- val size = buf.size
1081- val mbrs = List (name, name.toTypeName).flatMap(path.tpe.member(_).alternatives)
1082- mbrs.foreach(addForwarder(alias, _, span))
1083- if (buf.size == size) {
1084- val reason = mbrs.map(whyNoForwarder).dropWhile(_ == SKIP ) match {
1085- case Nil => " "
1086- case why :: _ => i " \n $path. $name cannot be exported because it $why"
1055+ forwarder.info = avoidPrivateLeaks(forwarder)
1056+ forwarder.addAnnotations(sym.annotations)
1057+ val forwarderDef =
1058+ if (forwarder.isType) tpd.TypeDef (forwarder.asType)
1059+ else {
1060+ import tpd ._
1061+ val ref = path.select(sym.asTerm)
1062+ val ddef = tpd.DefDef (forwarder.asTerm, prefss =>
1063+ ref.appliedToArgss(adaptForwarderParams(Nil , sym.info, prefss))
1064+ )
1065+ if forwarder.isInlineMethod then
1066+ PrepareInlineable .registerInlineInfo(forwarder, ddef.rhs)
1067+ ddef
10871068 }
1088- report.error(i """ no eligible member $name at $path$reason""" , ctx.source.atSpan(span))
1069+
1070+ buf += forwarderDef.withSpan(span)
1071+ end addForwarder
1072+
1073+ def addForwardersNamed (name : TermName , alias : TermName , span : Span ): Unit = {
1074+ val size = buf.size
1075+ val mbrs = List (name, name.toTypeName).flatMap(path.tpe.member(_).alternatives)
1076+ mbrs.foreach(addForwarder(alias, _, span))
1077+ if (buf.size == size) {
1078+ val reason = mbrs.map(whyNoForwarder).dropWhile(_ == SKIP ) match {
1079+ case Nil => " "
1080+ case why :: _ => i " \n $path. $name cannot be exported because it $why"
10891081 }
1082+ report.error(i """ no eligible member $name at $path$reason""" , ctx.source.atSpan(span))
10901083 }
1084+ }
10911085
1092- def addWildcardForwardersNamed (name : TermName , span : Span ): Unit =
1093- List (name, name.toTypeName)
1094- .flatMap(path.tpe.memberBasedOnFlags(_, excluded = Private | Given | ConstructorProxy ).alternatives)
1095- .foreach(addForwarder(name, _, span)) // ignore if any are not added
1096-
1097- def addWildcardForwarders (seen : List [TermName ], span : Span ): Unit =
1098- val nonContextual = mutable.HashSet (seen : _* )
1099- for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags , excluded = PrivateOrSynthetic ) do
1100- if ! mbr.symbol.isSuperAccessor then
1101- // Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1102- // need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1103- val alias = mbr.name.toTermName
1104- if mbr.symbol.is(Given ) then
1105- if ! seen.contains(alias) && mbr.matchesImportBound(givenBound) then
1106- addForwarder(alias, mbr, span)
1107- else if ! nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
1108- nonContextual += alias
1109- addWildcardForwardersNamed(alias, span)
1110-
1111- def addForwarders (sels : List [untpd.ImportSelector ], seen : List [TermName ]): Unit = sels match
1112- case sel :: sels1 =>
1113- if sel.isWildcard then
1114- addWildcardForwarders(seen, sel.span)
1115- else
1116- if sel.rename != nme.WILDCARD then
1117- addForwardersNamed(sel.name, sel.rename, sel.span)
1118- addForwarders(sels1, sel.name :: seen)
1119- case _ =>
1086+ def addWildcardForwardersNamed (name : TermName , span : Span ): Unit =
1087+ List (name, name.toTypeName)
1088+ .flatMap(path.tpe.memberBasedOnFlags(_, excluded = Private | Given | ConstructorProxy ).alternatives)
1089+ .foreach(addForwarder(name, _, span)) // ignore if any are not added
1090+
1091+ def addWildcardForwarders (seen : List [TermName ], span : Span ): Unit =
1092+ val nonContextual = mutable.HashSet (seen : _* )
1093+ for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags , excluded = PrivateOrSynthetic ) do
1094+ if ! mbr.symbol.isSuperAccessor then
1095+ // Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1096+ // need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1097+ val alias = mbr.name.toTermName
1098+ if mbr.symbol.is(Given ) then
1099+ if ! seen.contains(alias) && mbr.matchesImportBound(givenBound) then
1100+ addForwarder(alias, mbr, span)
1101+ else if ! nonContextual.contains(alias) && mbr.matchesImportBound(wildcardBound) then
1102+ nonContextual += alias
1103+ addWildcardForwardersNamed(alias, span)
1104+
1105+ def addForwarders (sels : List [untpd.ImportSelector ], seen : List [TermName ]): Unit = sels match
1106+ case sel :: sels1 =>
1107+ if sel.isWildcard then
1108+ addWildcardForwarders(seen, sel.span)
1109+ else
1110+ if sel.rename != nme.WILDCARD then
1111+ addForwardersNamed(sel.name, sel.rename, sel.span)
1112+ addForwarders(sels1, sel.name :: seen)
1113+ case _ =>
11201114
1121- addForwarders(selectors, Nil )
1122- val forwarders = buf.toList
1123- exp.pushAttachment(ExportForwarders , forwarders)
1124- forwarders
1125- }
1115+ addForwarders(selectors, Nil )
1116+ val forwarders = buf.toList
1117+ exp.pushAttachment(ExportForwarders , forwarders)
1118+ forwarders
1119+ end exportForwarders
11261120
1127- for case exp @ Export (_, _) <- rest do
1128- for forwarder <- exportForwarders(exp) do
1129- forwarder.symbol.entered
1130- }
1121+ /** Add forwarders as required by the export statements in this class */
1122+ private def processExports (using Context ): Unit =
1123+
1124+ def process (stats : List [Tree ])(using Context ): Unit = stats match
1125+ case (stat : Export ) :: stats1 =>
1126+ for forwarder <- exportForwarders(stat) do
1127+ forwarder.symbol.entered
1128+ process(stats1)
1129+ case (stat : Import ) :: stats1 =>
1130+ process(stats1)(using ctx.importContext(stat, symbolOfTree(stat)))
1131+ case stat :: stats1 =>
1132+ process(stats1)
1133+ case Nil =>
1134+
1135+ // Do a quick scan whether we need to process at all. This avoids creating
1136+ // import contexts for nothing.
1137+ if rest.exists(_.isInstanceOf [Export ]) then
1138+ process(rest)
1139+ end processExports
11311140
11321141 /** Ensure constructor is completed so that any parameter accessors
11331142 * which have type trees deriving from its parameters can be
0 commit comments