private def lubInner()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/psi/types/ScalaBounds.scala [302:398]


  private def lubInner(t1: ScType, t2: ScType, depth : Int, checkWeak: Boolean)(implicit stopAddingUpperBound: Boolean, context: Context): ScType = {
    if (conforms(t1, t2, checkWeak)) t2
    else if (conforms(t2, t1, checkWeak)) t1
    else {
      def lubWithExpandedAliases(t1: ScType, t2: ScType): ScType = {
        (t1, t2) match {
          case (TypeConstructor(poly), _) =>
            lubInner(poly, t2, depth, checkWeak)
          case (_, TypeConstructor(poly)) =>
            lubInner(t1, poly, depth, checkWeak)
          case (ScDesignatorType(t: ScParameter), _) =>
            lubInner(t.insideParamType.getOrAny, t2, depth, checkWeak)
          case (ScDesignatorType(t: ScTypedDefinition), _) if !t.is[ScObject] =>
            lubInner(t.`type`().getOrAny, t2, depth, checkWeak)
          case (_, ScDesignatorType(t: ScParameter)) =>
            lubInner(t1, t.insideParamType.getOrAny, depth, checkWeak)
          case (_, ScDesignatorType(t: ScTypedDefinition)) if !t.is[ScObject] =>
            lubInner(t1, t.`type`().getOrAny, depth, checkWeak)
          case (ex: ScExistentialType, _) => lubInner(ex.quantified, t2, depth, checkWeak).unpackedType
          case (_, ex: ScExistentialType) => lubInner(t1, ex.quantified, depth, checkWeak).unpackedType
          case (tpt: TypeParameterType, _) if !stopAddingUpperBound => lubInner(tpt.upperType, t2, depth - 1, checkWeak)
          case (_, tpt: TypeParameterType) if !stopAddingUpperBound => lubInner(t1, tpt.upperType, depth - 1, checkWeak)
          case (arg @ ScExistentialArgument(_, _, lower, upper), ScExistentialArgument(_, _, lower2, upper2))
            if !stopAddingUpperBound =>
            arg.copyWithBounds(glb(lower, lower2, checkWeak), lubInner(upper, upper2, depth - 1, checkWeak))
          case (arg @ ScExistentialArgument(_, _, lower, upper), r) if !stopAddingUpperBound =>
            arg.copyWithBounds(glb(lower, r, checkWeak), lubInner(upper, t2, depth - 1, checkWeak))
          case (r, arg @ ScExistentialArgument(_, _, lower, upper)) if !stopAddingUpperBound =>
            arg.copyWithBounds(glb(lower, r, checkWeak), lubInner(upper, t2, depth - 1, checkWeak))
          case (_: ValType, _: ValType) => AnyVal
          case (lit1: ScLiteralType, lit2: ScLiteralType) => lubInner(lit1.wideType, lit2.wideType, depth, checkWeak = true)
          case (JavaArrayType(arg1), JavaArrayType(arg2)) =>
            val (v, ex) = calcForTypeParamWithoutVariance(arg1, arg2, checkWeak)
            ex match {
              case Some(_) => ScExistentialType(JavaArrayType(v))
              case None    => JavaArrayType(v)
            }
          case (JavaArrayType(arg), ParameterizedType(des, args)) if args.length == 1 && (des.extractClass match {
            case Some(q) => q.qualifiedName == "scala.Array"
            case _ => false
          }) =>
            val (v, ex) = calcForTypeParamWithoutVariance(arg, args.head, checkWeak)
            ex match {
              case Some(_) => ScExistentialType(ScParameterizedType(des, Seq(v)))
              case None    => ScParameterizedType(des, Seq(v))
            }
          case (ParameterizedType(des, args), JavaArrayType(arg)) if args.length == 1 && (des.extractClass match {
            case Some(q) => q.qualifiedName == "scala.Array"
            case _ => false
          }) =>
            val (v, ex) = calcForTypeParamWithoutVariance(arg, args.head, checkWeak)
            ex match {
              case Some(_) => ScExistentialType(ScParameterizedType(des, Seq(v)))
              case None    => ScParameterizedType(des, Seq(v))
            }
          case (JavaArrayType(_), tp) =>
            if (tp.conforms(AnyRef)) AnyRef
            else Any
          case (tp, JavaArrayType(_)) =>
            if (tp.conforms(AnyRef)) AnyRef
            else Any
          case (lhs: ScTypePolymorphicType, rhs: ScTypePolymorphicType) =>
            polymorphicTypesBound(lhs, rhs, BoundKind.Lub, checkWeak, depth)
          case _ =>
            val leftClasses: Seq[ClassLike] = {
              t1 match {
                case ScCompoundType(comps1, _, _) => comps1.map(new ClassLike(_))
                case _ => Seq(new ClassLike(t1))
              }
            }
            val rightClasses: Seq[ClassLike] = {
              t2 match {
                case ScCompoundType(comps1, _, _) => comps1.map(new ClassLike(_))
                case _ => Seq(new ClassLike(t2))
              }
            }
            if (leftClasses.exists(_.isEmpty) || rightClasses.exists(_.isEmpty)) Any
            else {
              val buf = new ArrayBuffer[ScType]
              val supers: Array[(ClassLike, Int, Int)] =
                getLeastUpperClasses(leftClasses, rightClasses)
              for (sup <- supers) {
                val tp = getTypeForAppending(leftClasses(sup._2), rightClasses(sup._3), sup._1, depth, checkWeak)
                if (tp != Any) buf += tp
              }
              buf.toArray match {
                case a: Array[ScType] if a.length == 0 => Any
                case a: Array[ScType] if a.length == 1 => a(0)
                case many                              => ScCompoundType(many.toSeq, Map.empty, Map.empty)
              }
            }
          //todo: refinement for compound types
        }
      }
      lubWithExpandedAliases(t1, t2).unpackedType
    }
  }