private def checkPatternType()

in scala/scala-impl/src/org/jetbrains/plugins/scala/annotator/element/ScPatternAnnotator.scala [58:257]


  private def checkPatternType(_patType: ScType, exprType: ScType, pattern: ScPattern)
                              (implicit holder: ScalaAnnotationHolder): Unit = {
    import pattern.projectContext
    implicit val tpc: TypePresentationContext = TypePresentationContext(pattern)
    implicit val context: Context = Context(pattern)

    val dealiased = ScalaType.expandAliases(exprType).getOrElse(exprType)
    val exTp      = widen(dealiased)
    val patType   = _patType.removeAliasDefinitions()

    def freeTypeParams = freeTypeParamsOfTerms(dealiased)

    def exTpMatchesPattp = matchesPattern(exTp, widen(patType))

    def hasNoFreeTypeVariables(pattern: ScPattern): Boolean =
      pattern.typeVariables.isEmpty && freeTypeParams.isEmpty

    lazy val patternTypeAsTuple =
      ExtractorMatch.ByNameExtractor(pattern).unapply(patType).map {
        productElements =>
          TupleType(productElements, context = pattern)
      }

    lazy val neverMatches =
      !matchesPattern(exTp, patternTypeAsTuple.getOrElse(patType)) &&
        isNeverSubType(abstraction(patType), exTp) &&
        hasNoFreeTypeVariables(pattern) &&
        !(patType.isNumericType && exTp.isNumericType)

    def isEliminatedByErasure = (exprType.extractClass, patType.extractClass) match {
      case (Some(cl1), Some(cl2)) if pattern.is[ScTypedPattern] => !isNeverSubClass(cl1, cl2)
      case _ => false
    }

    def isTupleAsInfixArgList: Boolean =
      pattern.asOptionOf[ScTuplePattern].exists(_.infixPatternOfWhichThisIsTheArgPatternList.isDefined)

    object StableIdResolvesToVar {

      def unapply(stable: ScStableReferencePattern): Boolean = stable match {
        case ScStableReferencePattern(ResolvesTo(inNameContext(context))) =>
          context match {
            case param: ScClassParameter => param.isVar
            case _: ScVariable => true
            case _ => false
          }
        case _ => false
      }
    }

    pattern match {
      case _: ScTypedPatternLike if Seq(Nothing, Null, AnyVal) contains patType =>
        val message = ScalaBundle.message("type.cannot.be.used.in.type.pattern", patType.presentableText)
        holder.createErrorAnnotation(pattern, message)
      case _: ScTypedPatternLike if exTp.isFinalType && freeTypeParams.isEmpty && !exTpMatchesPattp =>
        val (exprTypeText, patTypeText) = TypePresentation.different(exprType, patType)
        val message = ScalaBundle.message("scrutinee.incompatible.pattern.type", patTypeText, exprTypeText)
        holder.createErrorAnnotation(pattern, message)
      case ScTypedPattern(typeElem @ ScCompoundTypeElement(_, Some(_))) =>
        val message = ScalaBundle.message("pattern.on.refinement.unchecked")
        holder.createWarningAnnotation(typeElem, message)
      case _: ScExtractorPattern if neverMatches && patType.isFinalType =>
        val message = ScalaBundle.message("constructor.cannot.be.instantiated.to.expected.type", patType, exprType)
        holder.createErrorAnnotation(pattern, message)
      case _: ScTuplePattern | _: ScInfixPattern if !isTupleAsInfixArgList && neverMatches =>
        val message = ScalaBundle.message("pattern.type.incompatible.with.expected", patType, exprType)
        holder.createErrorAnnotation(pattern, message)
      case nt: ScNamedTuplePattern =>
        exprType match {
          case NamedTupleType(comps) =>
            val map = NamedTupleType.makeComponentMap(comps)
            val seen = mutable.Set.empty[String]
            nt.components.foreach {
              case comp@ScNamedTuplePatternComponent(name, _) =>
                val nameElement = comp.nameElement.get
                if (!seen.add(name)) {
                  holder.createErrorAnnotation(nameElement, ScalaBundle.message("duplicated.name.extractor.name", name))
                }
                if (!map.contains(name)) {
                  val message = ScalaBundle.message("cannot.extract.name.from.selector.type", name, exprType.presentableText)
                  holder.createErrorAnnotation(nameElement, message)
                }
              case _: ScNamedConstructorArgPattern => // for when the name element was omitted
              case pat =>
                holder.createErrorAnnotation(pat, ScalaBundle.message("cannot.use.positional.pattern.when.named.patterns.are.used"))
            }
          case _ =>
            val message = ScalaBundle.message("type.cannot.be.matched.by.a.named.tuple.pattern", exprType.presentableText)
            holder.createErrorAnnotation(nt, message)
        }
      case _  if patType.isFinalType && neverMatches =>
        val (exprTypeText, patTypeText) = TypePresentation.different(exprType, patType)
        val message = ScalaBundle.message("pattern.type.incompatible.with.expected", patTypeText, exprTypeText)
        holder.createErrorAnnotation(pattern, message)
      case _: ScTypedPatternLike | _: ScExtractorPattern if neverMatches =>
        val erasureWarn =
          if (isEliminatedByErasure) ScalaBundle.message("erasure.warning")
          else ""
        val (exprTypeText, patTypeText) = TypePresentation.different(exprType, patType)
        val baseMessage = ScalaBundle.message("fruitless.type.test", exprTypeText, patTypeText)
        holder.createWarningAnnotation(pattern, NlsString.force(baseMessage + erasureWarn))
      case StableIdResolvesToVar() =>
        val message = ScalaBundle.message("stable.identifier.required", pattern.getText)
        holder.createErrorAnnotation(pattern, message)
      case Implicit0Pattern(arg) =>
        arg match {
          case ScTypedPattern(_) => () // valid according to better-monadic-for rewriting rules
          case _ => holder.createErrorAnnotation(arg, ScalaBundle.message("better.monadic.for.invalid.pattern"))
        }
      case _: ScInterpolationPattern => //do not check interpolated patterns for number of arguments
      case extractorPattern: ScExtractorPattern => //check number of arguments
        val argPatterns = extractorPattern.argPatterns
        val numPatterns = argPatterns.length
        val argPatternsShape = extractorPattern.argPatternShape

        extractorPattern.targetFor(Some(exprType)) match {
          case Some(target@ExtractorTarget.UnapplyMatches(matches)) if !target.isMacroExtractor =>
              if (matches.isEmpty) {
                target match {
                  case ExtractorTarget.Function.Returning(rt) =>
                    holder.createErrorAnnotation(pattern, ScalaBundle.message("type.is.not.a.valid.result.type.of.an.unapply.method", rt.presentableText))
                  case _ =>
                    // this is either ExtractorTarget.TooBigCaseClass and shouldn't happen at all because there should always be a match for TooBigCaseClass
                    // Or the return type of the function can not be resolved... in that case also don't give an error
                }

              } else if (argPatternsShape.hasNamedArgs) {
                val extractorMatch = matches.find(_.supportsNamedPatterns)
                extractorMatch match {
                  case Some(extractorMatch) =>
                    val namedPatterns = extractorMatch.namedPatternTypes(pattern)
                    val seen = mutable.Set.empty[String]
                    argPatterns.foreach {
                      case pat@ScNamedConstructorArgPattern(name, _) =>
                        val nameElement = pat.nameElement.get
                        if (!seen.add(name)) {
                          holder.createErrorAnnotation(nameElement, ScalaBundle.message("duplicated.name.extractor.name", name))
                        }
                        if (!namedPatterns.contains(name)) {
                          val message = ScalaBundle.message("cannot.extract.name.from.selector.type", name, extractorMatch.selectorType.presentableText)
                          holder.createErrorAnnotation(nameElement, message)
                        }
                      case _: ScNamedConstructorArgPattern => // for when the name element was omitted
                      case pat =>
                        holder.createErrorAnnotation(pat, ScalaBundle.message("cannot.use.positional.pattern.when.named.patterns.are.used"))
                    }
                  case None =>
                    target.selectorType.foreach { unapplyType =>
                      val message = ScalaBundle.message("type.does.not.support.named.patterns", unapplyType.presentableText)
                      holder.createErrorAnnotation(pattern, message)
                    }
                }
              }else if (!matches.hasApplicable(argPatternsShape)) {
                matches.findApplicable(argPatternsShape.copy(seqAtEnd = false)) match {
                  case Some(m) =>
                    val matchedType = m.productTypes.last.presentableText
                    holder.createErrorAnnotation(argPatterns.last, ScalaBundle.message("cannot.match.type.with.sequence.pattern", matchedType))
                  case None =>
                    val expected = matches.map(_.productTypes.length).max
                    val message = ScalaBundle.message("wrong.number.arguments.extractor", numPatterns.toString, expected)
                    holder.createErrorAnnotation(pattern, message)
                }
              }
          case Some(target@ExtractorTarget.UnapplySeqMatches(matches)) if !target.isMacroExtractor =>
            if (matches.isEmpty) {
              target match {
                case ExtractorTarget.Function.Returning(rt) =>
                  holder.createErrorAnnotation(pattern, ScalaBundle.message("type.is.not.a.valid.result.type.of.an.unapplyseq.method", rt.presentableText))
                case _ =>
                  // this is either ExtractorTarget.TooBigCaseClass and shouldn't happen at all because there should always be a match for TooBigCaseClass
                  // Or the return type of the function can not be resolved... in that case also don't give an error
              }
            } else if (!matches.hasApplicable(argPatternsShape)) {
              val expected = matches.map(_.productTypes.length).max
              val message = ScalaBundle.message("wrong.number.arguments.extractor.unapplySeq", numPatterns.toString, expected)
              holder.createErrorAnnotation(pattern, message)
            }
          case _ =>
        }
      case _ =>
    }

    if (pattern.isInScala3File) {
      val nonPattern = pattern.contexts
        .takeWhile(e => !e.is[ScExpression, ScBlockStatement] || e.is[ScValueOrVariableDefinition, ScPattern])
        .find(_.is[ScGenerator, ScValueOrVariableDefinition])

      def isIrrefutable = pattern.isIrrefutableFor(exprType, deep = false)
      def message = ScalaBundle.message("pattern.is.not.irrefutable.for.exprType", pattern.getText, exprType.presentableText)

      nonPattern match {
        case Some(gen: ScGenerator) if gen.caseKeyword.isEmpty && !isIrrefutable =>
          val quickfix = new AddCaseToGeneratorQuickfix(gen)
          holder.createWarningAnnotation(pattern, message, quickfix)
        case Some(v: ScValueOrVariableDefinition) if !v.expr.exists(ScalaPsiUtil.isUncheckedExpr) && !isIrrefutable =>
          holder.createWarningAnnotation(pattern, message)
        case _ =>
      }
    }
  }