@@ -667,50 +667,40 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
667
667
assert(isScalaClass || isInterface,
668
668
s " Cannot call lookupMethod( $methodName) on non Scala class $this" )
669
669
670
- @ tailrec
671
- def tryLookupInherited (ancestorInfo : ClassInfo ): Option [MethodInfo ] = {
672
- ancestorInfo.publicMethodInfos.get(methodName) match {
673
- case Some (m) if ! m.isAbstract && (! m.nonExistent || ancestorInfo == this ) =>
674
- Some (m)
675
- case _ =>
676
- ancestorInfo.superClass match {
677
- case Some (superClass) => tryLookupInherited(superClass)
678
- case None => None
670
+ publicMethodInfos.get(methodName) match {
671
+ case Some (m) if ! m.isAbstract => Some (m)
672
+
673
+ case _ =>
674
+ val candidate = superClass
675
+ .flatMap(_.tryLookupMethod(methodName))
676
+ .filterNot(_.nonExistent)
677
+
678
+ if (allowAddingSyntheticMethods) {
679
+ def maybeDefaultTarget = getDefaultTarget(methodName)
680
+
681
+ def needsDefaultOverride (method : MethodInfo ): Boolean = {
682
+ /* The .get is OK, since we only get here if:
683
+ * - This class doesn't implement the method directly.
684
+ * - The superClass has found a default target.
685
+ * In this case, we always find at least one target.
686
+ */
687
+ method.isDefaultBridge && method.defaultBridgeTarget != maybeDefaultTarget.get.owner.className
679
688
}
680
- }
681
- }
682
- val existing =
683
- if (isScalaClass) tryLookupInherited(this )
684
- else publicMethodInfos.get(methodName).filter(! _.isAbstract)
685
689
686
- if (! allowAddingSyntheticMethods) {
687
- existing
688
- } else if (existing.exists(m => ! m.isDefaultBridge || m.owner == this )) {
689
- /* If we found a non-bridge, it must be the right target.
690
- * If we found a bridge directly in this class/interface, it must also
691
- * be the right target.
692
- */
693
- existing
694
- } else {
695
- // Try and find the target of a possible default bridge
696
- findDefaultTarget(methodName).fold {
697
- assert(existing.isEmpty)
698
- existing
699
- } { defaultTarget =>
700
- if (existing.exists(_.defaultBridgeTarget == defaultTarget.owner.className)) {
701
- /* If we found an existing bridge targeting the right method, we
702
- * can reuse it.
703
- * We also get here with None when there is no target whatsoever.
704
- */
705
- existing
690
+ candidate
691
+ .filterNot(needsDefaultOverride(_))
692
+ .orElse(maybeDefaultTarget.map(createDefaultBridge(_)))
706
693
} else {
707
- // Otherwise, create a new default bridge
708
- Some (createDefaultBridge(defaultTarget))
694
+ candidate
709
695
}
710
- }
711
696
}
712
697
}
713
698
699
+ private val defaultTargets = mutable.Map .empty[MethodName , Option [MethodInfo ]]
700
+
701
+ private def getDefaultTarget (methodName : MethodName ): Option [MethodInfo ] =
702
+ defaultTargets.getOrElseUpdate(methodName, findDefaultTarget(methodName))
703
+
714
704
/** Resolves an inherited default method.
715
705
*
716
706
* This lookup is specified by the JVM resolution rules for default
0 commit comments