override def visitParameterizedType()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/psi/types/ScalaConformance.scala [977:1191]


    override def visitParameterizedType(p: ParameterizedType): Unit = {
      var rightVisitor: ScalaTypeVisitor =
        new ValDesignatorSimplification with UndefinedSubstVisitor with AbstractVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      p.designator match {
        case DesignatorOwner(ta: ScTypeAlias) if p.typeArguments.size == 1 =>
          val containingClassName = Option(ta.containingClass).map(_.qualifiedName).orNull

          if (containingClassName == "scala.compiletime.ops.int" && ta.name == "S") {
            r match {
              case ScLiteralType(ScIntegerLiteralImpl.Value(int), _) if int > 0 =>
                val tvar = p.typeArguments.head
                val decremented = ScIntegerLiteralImpl.Value(int - 1)
                result = equivInner(tvar, ScLiteralType(decremented)(projectContext), constraints, falseUndef = false)
                return
              case _ => ()
            }
          }
        case a: ScAbstractType =>
          val subst = ScSubstitutor.bind(a.typeParameter.typeParameters, p.typeArguments)
          val upper: ScType =
            subst(a.upper) match {
              case up if up.equiv(Any)      => Any
              case ParameterizedType(up, _) => ScParameterizedType(up, p.typeArguments)
              case up                       => ScParameterizedType(up, p.typeArguments)
            }

          if (!upper.equiv(Any)) {
            result = conformsInner(upper, r, visited, constraints, checkWeak)
          } else {
            result = constraints
          }
          if (result.isRight) {
            val lower: ScType =
              subst(a.lower) match {
                case low if low.equiv(Nothing) => Nothing
                case ParameterizedType(low, _) => ScParameterizedType(low, p.typeArguments)
                case low                       => ScParameterizedType(low, p.typeArguments)
              }
            if (!lower.equiv(Nothing)) {
              val t = conformsInner(r, lower, visited, result.constraints, checkWeak)
              if (t.isRight) result = t
            }
          }
          return
        case _ =>
      }

      rightVisitor = new ParameterizedAbstractVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      checkEquiv()
      if (result ne null) return

      rightVisitor = new ExistentialSimplification with ExistentialArgumentVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      p.designator match {
        case s: ScExistentialArgument =>
          s.lower match {
            case ParameterizedType(lower, _) =>
              result = conformsInner(lower, r, visited, constraints, checkWeak)
              return
            case lower =>
              result = conformsInner(lower, r, visited, constraints, checkWeak)
              return
          }
        case _ =>
      }

      rightVisitor = new ParameterizedExistentialArgumentVisitor with OtherNonvalueTypesVisitor with NothingNullVisitor
         with ThisVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      r match {
        case ScalaArrayType(rightArg) =>
          p match {
            case ScalaArrayType(leftArg) => result = checkArrayArgs(leftArg, rightArg)
            case _                       =>
          }
        case p2: ScParameterizedType =>
          val des1 = p.designator
          val des2 = p2.designator
          val args1 = p.typeArguments
          val args2 = p2.typeArguments
          (des1, des2) match {
            case (lhs: TypeParameterType, _: TypeParameterType) =>
              if (des1.equiv(des2)) {
                if (args1.length != args2.length) {
                  result = ConstraintsResult.Left
                } else {
                  result = checkParameterizedType(lhs.typeParameters, args1, args2,
                    constraints, visited, checkWeak)
                }
              } else result = retryTypeParamsConformance(lhs, l, r, constraints)
            case (UndefinedType(_, _), UndefinedType(typeParameter, _)) =>
              if (TypeVariableUnification.unifiableKinds(p, p2)) {
                constraints = constraints.withUpper(typeParameter.typeParamId, des1)

                result = checkParameterizedType(
                  typeParameter.typeParameters,
                  args1, args2, constraints,
                  visited, checkWeak
                )
              } else result = ConstraintsResult.Left
            case (UndefinedType(_, _), _) => result = unifyHK(p, p2, constraints, Bound.Lower, visited, checkWeak)
            case (_, UndefinedType(_, _)) => result = unifyHK(p2, p, constraints, Bound.Upper, visited, checkWeak)
            case _ if des1 equiv des2 =>
              result =
                if (args1.length != args2.length) ConstraintsResult.Left
                else {
                  val tparams = extractTypeParameters(des1)
                  if (tparams.isEmpty) ConstraintsResult.Left
                  else                 checkParameterizedType(tparams, args1, args2, constraints, visited, checkWeak)
                }
            case (_, t: TypeParameterType) if t.typeParameters.length == p2.typeArguments.length =>
              val upper = {
                val upper = t.upperType
                upper.typeConstructor.getOrElse(upper)
              }

              val subst = upper match {
                case ScTypePolymorphicType(_, tparams) => ScSubstitutor.bind(tparams, p2.typeArguments)
                case _                                 => ScSubstitutor.bind(t.typeParameters, p2.typeArguments)
              }

              result = conformsInner(ScTypePolymorphicType(p, t.typeParameters), subst(upper), visited, constraints, checkWeak)
            case (proj1: ScProjectionType, proj2: ScProjectionType)
              if smartEquivalence(proj1.actualElement, proj2.actualElement) =>
              val t = conformsInner(proj1, proj2, visited, constraints)
              if (t.isLeft) {
                result = ConstraintsResult.Left
              } else {
                constraints = t.constraints
                if (args1.length != args2.length) {
                  result = ConstraintsResult.Left
                } else {
                  proj1.actualElement match {
                    case td: ScTypeParametersOwner =>
                      val tps = td.typeParameters.map(TypeParameter(_))
                      result = checkParameterizedType(tps, args1, args2, constraints, visited, checkWeak)
                    case td: PsiTypeParameterListOwner =>
                      val tps = td.getTypeParameters.map(TypeParameter(_))
                      result = checkParameterizedType(tps, args1, args2, constraints, visited, checkWeak)
                    case _ =>
                      result = ConstraintsResult.Left
                  }
                }
              }
            case _ =>
          }
        case _ =>
      }

      if (result != null) {
        //sometimes when the above part has failed, we still have to check for alias
        if (!result.isRight && r.isAliasType) {
          rightVisitor = new ParameterizedAliasVisitor with TypeParameterTypeVisitor {}
          r.visitType(rightVisitor)
        }

        if (result.isRight) return
        else l match {
          case AliasType(_, Right(lower), _, _) =>
            result = conformsInner(lower, r, visited, constraints)
          case _ => return
        }

        return
      }

      rightVisitor = new ParameterizedAliasVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      r match {
        case JavaArrayType(rightArg) =>
          p match {
            case ScalaArrayType(leftArg) =>
              result = checkArrayArgs(leftArg, rightArg)
            case _ =>
          }
        case _ =>
      }

      if (result != null) return

      rightVisitor = new AliasDesignatorVisitor with MatchTypeVisitor with CompoundTypeVisitor with ExistentialVisitor
        with ProjectionVisitor with OrTypeVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      p match {
        case AliasType(_, lower, _, _) =>
          lower match {
            case Right(value) if !value.isNothing =>
              result = conformsInner(value, r, visited, constraints)
              if (result != null) return
            case _                                => ()
          }
        case _ =>
      }

      rightVisitor = new DesignatorVisitor {}
      r.visitType(rightVisitor)
      if (result != null) return

      rightVisitor = new TypeParameterTypeVisitor {}
      r.visitType(rightVisitor)
    }