@@ -353,7 +353,21 @@ object SymDenotations {
353353 /** The completer of this denotation. @pre: Denotation is not yet completed */
354354 final def completer : LazyType = myInfo.asInstanceOf [LazyType ]
355355
356- /** Make sure this denotation is completed */
356+ /** If this denotation is not completed, run the completer.
357+ * The resulting info might be another completer.
358+ *
359+ * @see ensureCompleted
360+ */
361+ final def completeOnce ()(implicit ctx : Context ): Unit = myInfo match {
362+ case myInfo : LazyType =>
363+ completeFrom(myInfo)
364+ case _ =>
365+ }
366+
367+ /** Make sure this denotation is fully completed.
368+ *
369+ * @see completeOnce
370+ */
357371 final def ensureCompleted ()(implicit ctx : Context ): Unit = info
358372
359373 /** The symbols defined in this class or object.
@@ -370,7 +384,7 @@ object SymDenotations {
370384 case cinfo : LazyType =>
371385 val knownDecls = cinfo.decls
372386 if (knownDecls ne EmptyScope ) knownDecls
373- else { completeFrom(cinfo ); unforcedDecls } // complete-once
387+ else { completeOnce( ); unforcedDecls }
374388 case _ => info.decls
375389 }
376390
@@ -505,20 +519,33 @@ object SymDenotations {
505519 /** is this symbol the result of an erroneous definition? */
506520 def isError : Boolean = false
507521
508- /** Make denotation not exist */
509- final def markAbsent (): Unit =
522+ /** Make denotation not exist.
523+ * @pre `isCompleting` is false, or this is a ModuleCompleter or SymbolLoader
524+ */
525+ final def markAbsent ()(implicit ctx : Context ): Unit = {
526+ if (isCompleting)
527+ assert(myInfo.isInstanceOf [ModuleCompleter | SymbolLoader ],
528+ s " Illegal call to `markAbsent()` while completing $this using completer $myInfo" )
510529 myInfo = NoType
530+ }
511531
512- /** Is symbol known to not exist, or potentially not completed yet? */
513- final def unforcedIsAbsent (implicit ctx : Context ): Boolean =
514- myInfo == NoType ||
515- (this .is(ModuleVal , butNot = Package )) && moduleClass.unforcedIsAbsent
516-
517- /** Is symbol known to not exist? */
518- final def isAbsent (implicit ctx : Context ): Boolean = {
519- ensureCompleted()
520- (myInfo `eq` NoType ) ||
521- (this .is(ModuleVal , butNot = Package )) && moduleClass.isAbsent
532+ /** Is symbol known to not exist?
533+ * @param canForce If this is true, the info may be forced to avoid a false-negative result
534+ */
535+ @ tailrec
536+ final def isAbsent (canForce : Boolean = true )(implicit ctx : Context ): Boolean = myInfo match {
537+ case myInfo : ModuleCompleter =>
538+ // Instead of completing the ModuleCompleter, we can check whether
539+ // the module class is absent, which might require less completions.
540+ myInfo.moduleClass.isAbsent(canForce)
541+ case _ : SymbolLoader if canForce =>
542+ // Completing a SymbolLoader might call `markAbsent()`
543+ completeOnce()
544+ isAbsent(canForce)
545+ case _ =>
546+ // Otherwise, no completion is necessary, see the preconditions of `markAbsent()`.
547+ (myInfo `eq` NoType ) ||
548+ is(ModuleVal , butNot = Package ) && moduleClass.isAbsent(canForce)
522549 }
523550
524551 /** Is this symbol the root class or its companion object? */
@@ -639,7 +666,7 @@ object SymDenotations {
639666 final def isCoDefinedWith (other : Symbol )(implicit ctx : Context ): Boolean =
640667 (this .effectiveOwner == other.effectiveOwner) &&
641668 ( ! this .effectiveOwner.is(PackageClass )
642- || this .unforcedIsAbsent || other.unforcedIsAbsent
669+ || this .isAbsent(canForce = false ) || other.isAbsent(canForce = false )
643670 || { // check if they are defined in the same file(or a jar)
644671 val thisFile = this .symbol.associatedFile
645672 val thatFile = other.associatedFile
@@ -792,7 +819,7 @@ object SymDenotations {
792819 }
793820
794821 if (pre eq NoPrefix ) true
795- else if (isAbsent) false
822+ else if (isAbsent() ) false
796823 else {
797824 val boundary = accessBoundary(owner)
798825
@@ -1611,7 +1638,7 @@ object SymDenotations {
16111638 }
16121639
16131640 final override def derivesFrom (base : Symbol )(implicit ctx : Context ): Boolean =
1614- ! isAbsent &&
1641+ ! isAbsent() &&
16151642 base.isClass &&
16161643 ( (symbol eq base)
16171644 || (baseClassSet contains base)
@@ -1990,7 +2017,7 @@ object SymDenotations {
19902017
19912018 /** Register companion class */
19922019 override def registerCompanion (companion : Symbol )(implicit ctx : Context ) =
1993- if (companion.isClass && ! unforcedIsAbsent && ! companion.unforcedIsAbsent )
2020+ if (companion.isClass && ! isAbsent(canForce = false ) && ! companion.isAbsent(canForce = false ) )
19942021 myCompanion = companion
19952022
19962023 override def registeredCompanion (implicit ctx : Context ) = { ensureCompleted(); myCompanion }
@@ -2072,7 +2099,7 @@ object SymDenotations {
20722099 }
20732100 case nil =>
20742101 val directMembers = super .computeNPMembersNamed(name)
2075- if (acc.exists) acc.union(directMembers.filterWithPredicate(! _.symbol.isAbsent))
2102+ if (acc.exists) acc.union(directMembers.filterWithPredicate(! _.symbol.isAbsent() ))
20762103 else directMembers
20772104 }
20782105 if (symbol `eq` defn.ScalaPackageClass ) {
0 commit comments