@@ -13,6 +13,7 @@ import config.SourceVersion
1313import StdNames .nme
1414import printing .Texts .Text
1515import ProtoTypes .NoViewsAllowed .normalizedCompatible
16+ import NameKinds .QualifiedName
1617import Decorators ._
1718
1819object ImportInfo {
@@ -33,7 +34,7 @@ object ImportInfo {
3334 val expr = tpd.Ident (ref.refFn()) // refFn must be called in the context of ImportInfo.sym
3435 tpd.Import (expr, selectors).symbol
3536
36- ImportInfo (sym, selectors, None , isRootImport = true )
37+ ImportInfo (sym, selectors, untpd. EmptyTree , isRootImport = true )
3738
3839 extension (c : Context )
3940 def withRootImports (rootRefs : List [RootRef ])(using Context ): Context =
@@ -42,23 +43,27 @@ object ImportInfo {
4243 def withRootImports : Context =
4344 given Context = c
4445 c.withRootImports(defn.rootImportFns)
45-
4646}
4747
4848/** Info relating to an import clause
49- * @param sym The import symbol defined by the clause
49+ * @param symf A function that computes the import symbol defined by the clause
5050 * @param selectors The selector clauses
51- * @param symNameOpt Optionally, the name of the import symbol. None for root imports.
51+ * @param qualifier The import qualifier, or EmptyTree for root imports.
5252 * Defined for all explicit imports from ident or select nodes.
5353 * @param isRootImport true if this is one of the implicit imports of scala, java.lang,
5454 * scala.Predef in the start context, false otherwise.
5555 */
5656class ImportInfo (symf : Context ?=> Symbol ,
5757 val selectors : List [untpd.ImportSelector ],
58- symNameOpt : Option [ TermName ] ,
58+ val qualifier : untpd. Tree ,
5959 val isRootImport : Boolean = false ) extends Showable {
6060
61- def sym (using Context ): Symbol = {
61+ private def symNameOpt = qualifier match {
62+ case ref : untpd.RefTree => Some (ref.name.asTermName)
63+ case _ => None
64+ }
65+
66+ def importSym (using Context ): Symbol = {
6267 if (mySym == null ) {
6368 mySym = symf
6469 assert(mySym != null )
@@ -68,7 +73,7 @@ class ImportInfo(symf: Context ?=> Symbol,
6873 private var mySym : Symbol = _
6974
7075 /** The (TermRef) type of the qualifier of the import clause */
71- def site (using Context ): Type = sym .info match {
76+ def site (using Context ): Type = importSym .info match {
7277 case ImportType (expr) => expr.tpe
7378 case _ => NoType
7479 }
@@ -177,28 +182,50 @@ class ImportInfo(symf: Context ?=> Symbol,
177182 assert(myUnimported != null )
178183 myUnimported
179184
180- private var myUnimported : Symbol = _
185+ private val isLanguageImport : Boolean = untpd.isLanguageImport(qualifier)
181186
182- private var myOwner : Symbol = null
183- private var myResults : SimpleIdentityMap [TermName , java.lang.Boolean ] = SimpleIdentityMap .empty
187+ private var myUnimported : Symbol = _
184188
185- /** Does this import clause or a preceding import clause import `owner.feature`? */
186- def featureImported (feature : TermName , owner : Symbol )(using Context ): Boolean =
189+ private var featureCache : SimpleIdentityMap [TermName , java.lang.Boolean ] = SimpleIdentityMap .empty
187190
188- def compute =
189- val isImportOwner = site.typeSymbol.eq(owner)
190- if isImportOwner && forwardMapping.contains(feature) then true
191- else if isImportOwner && excluded.contains(feature) then false
192- else
193- var c = ctx.outer
194- while c.importInfo eq ctx.importInfo do c = c.outer
195- (c.importInfo != null ) && c.importInfo.featureImported(feature, owner)(using c)
196-
197- if myOwner.ne(owner) || ! myResults.contains(feature) then
198- myOwner = owner
199- myResults = myResults.updated(feature, compute)
200- myResults(feature)
201- end featureImported
191+ /** Does this import clause or a preceding import clause enable or disable `feature`?
192+ * @param feature See featureImported for a description
193+ * @return Some(true) if `feature` is imported
194+ * Some(false) if `feature` is excluded
195+ * None if `feature` is not mentioned, or this is not a language import
196+ */
197+ def mentionsFeature (feature : TermName )(using Context ): Option [Boolean ] =
198+ def test (prefix : TermName , feature : TermName ): Option [Boolean ] =
199+ untpd.languageImport(qualifier) match
200+ case Some (`prefix`) =>
201+ if forwardMapping.contains(feature) then Some (true )
202+ else if excluded.contains(feature) then Some (false )
203+ else None
204+ case _ => None
205+ feature match
206+ case QualifiedName (prefix, name) => test(prefix, name)
207+ case _ => test(EmptyTermName , feature)
208+
209+ /** Does this import clause or a preceding import clause enable `feature`?
210+ *
211+ * @param feature a possibly quailified name, e.g.
212+ * strictEquality
213+ * experimental.genericNumberLiterals
214+ *
215+ * An excluded feature such as `strictEquality => _` in a language import
216+ * means that preceding imports are not considered and the feature is not imported.
217+ */
218+ def featureImported (feature : TermName )(using Context ): Boolean =
219+ if ! featureCache.contains(feature) then
220+ featureCache = featureCache.updated(feature,
221+ mentionsFeature(feature) match
222+ case Some (bv) => bv
223+ case None =>
224+ var c = ctx.outer
225+ while c.importInfo eq ctx.importInfo do c = c.outer
226+ (c.importInfo != null ) && c.importInfo.featureImported(feature)(using c)
227+ )
228+ featureCache(feature)
202229
203230 def toText (printer : Printer ): Text = printer.toText(this )
204231}
0 commit comments