in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/psi/impl/expr/ScReferenceExpressionImpl.scala [320:603]
private def convertBindToType(bind: ScalaResolveResult): TypeResult = {
val srr = bind match {
case ScalaResolveResult.ApplyMethodInnerResolve(inner) => inner
case _ => bind
}
val fromType = srr.fromType
val unresolvedTypeParameters = srr.unresolvedTypeParameters.getOrElse(Seq.empty)
val matchClauseSubst = srr.matchClauseSubstitutor
val extensionOwner = srr.exportedInExtension
val inner: ScType = srr match {
case ScalaResolveResult(fun: ScFun, s) =>
fun.polymorphicType(s)
//prevent infinite recursion for recursive pattern reference
case ScalaResolveResult(self: ScSelfTypeElement, _) =>
val clazz = PsiTreeUtil.getContextOfType(self, true, classOf[ScTemplateDefinition])
ScThisReferenceImpl.getThisTypeForTypeDefinition(clazz, this) match {
case Right(value) => value
case failure => return failure
}
case r@ScalaResolveResult(refPatt: ScBindingPattern, s) =>
refPatt.nameContext match {
case pd: ScPatternDefinition if PsiTreeUtil.isContextAncestor(pd, this, true) => pd.declaredType match {
case Some(t) => t
case None => return Failure(ScalaBundle.message("no.declared.type.found"))
}
case vd: ScVariableDefinition if PsiTreeUtil.isContextAncestor(vd, this, true) => vd.declaredType match {
case Some(t) => t
case None => return Failure(ScalaBundle.message("no.declared.type.found"))
}
case _ =>
val result = r.intersectedReturnType.asTypeResult.orElse(refPatt.`type`())
result.map { tp =>
if (isStableContext(tp) && refPatt.isStable) {
r.fromType match {
case Some(fT) => ScProjectionType(fT, refPatt)
case None => ScalaType.designator(refPatt)
}
} else s(tp)
}.getOrElse(return result)
}
case r @ ScalaResolveResult(param: ScParameter, s) =>
val owner = param.owner match {
case f: ScPrimaryConstructor => f.containingClass
case _: ScFunctionExpr => null
case f => f
}
def isMethodDependent(function: ScFunction): Boolean = {
def checkte(te: ScTypeElement): Boolean = {
var res = false
te.accept(new ScalaRecursiveElementVisitor {
override def visitReference(ref: ScReference): Unit = {
if (ref.resolve() == param) res = true
super.visitReference(ref)
}
})
res
}
function.returnTypeElement match {
case Some(te) if checkte(te) => return true
case _ =>
}
!function.parameters.forall { param =>
param.typeElement match {
case Some(te) => !checkte(te)
case _ => true
}
}
}
val paramType = param.insideParamType
val stableTypeRequired = paramType.exists(isStableContext)
r.fromType match {
case Some(fT) if param.isVal && stableTypeRequired => ScProjectionType(fT, param)
case Some(ScThisType(clazz)) if owner != null && PsiTreeUtil.isContextAncestor(owner, this, true) &&
stableTypeRequired && owner.is[ScTypeDefinition] && owner == clazz => ScalaType.designator(param) //todo: think about projection from this type?
case _ if owner != null && PsiTreeUtil.isContextAncestor(owner, this, true) &&
stableTypeRequired && !owner.is[ScTypeDefinition] => ScalaType.designator(param)
case _ =>
owner match {
case function: ScFunction if PsiTreeUtil.isContextAncestor(function, this, true) &&
isMethodDependent(function) => ScalaType.designator(param)
case _ =>
s(paramType match {
case Right(tp) => tp
case _ => return paramType
})
}
}
case result @ ScalaResolveResult(fun: ScFunction, s) if fun.isProbablyRecursive =>
val maybeResult = result.intersectedReturnType.orElse(fun.definedReturnType.toOption)
fun.polymorphicType(
s,
maybeResult,
dropExtensionClauses = result.shouldDropExtensionClauses,
extensionOwner = extensionOwner
)
case result @ ScalaResolveResult(fun: ScFunction, s) =>
fun
.polymorphicType(
s,
result.intersectedReturnType,
dropExtensionClauses = result.shouldDropExtensionClauses,
extensionOwner = extensionOwner
)
.updateTypeOfDynamicCall(result.isDynamic)
case ScalaResolveResult(param: ScParameter, s) if param.isRepeatedParameter =>
val computeType = param.`type`() match {
case Right(tp) => s(tp)
case result => return result
}
computeType.tryWrapIntoSeqType
case ScalaResolveResult(obj: ScObject, _) =>
def tail =
fromType match {
case Some(tp) => ScProjectionType(tp, obj)
case _ => ScalaType.designator(obj)
}
//hack to add Eta expansion for case classes
if (obj.isSyntheticObject) {
def canEtaExpandPolymorphicCaseClass =
this.scalaLanguageLevel.exists(_ >= ScalaLanguageLevel.Scala_2_13)
ScalaPsiUtil.getCompanionModule(obj) match {
case Some(clazz) if clazz.isCase && (!clazz.hasTypeParameters || canEtaExpandPolymorphicCaseClass) =>
this.expectedType() match {
case Some(tp) =>
if (FunctionType.isFunctionType(tp)) {
val tp = tail
val processor = new MethodResolveProcessor(this, CommonNames.Apply, Nil, Nil, Nil)
processor.processType(tp, this)
val candidates = processor.candidates
if (candidates.length != 1) tail
else convertBindToType(candidates(0)).getOrElse(tail)
} else tail
case _ => tail
}
case _ => tail
}
} else tail
case r @ ScalaResolveResult(f: ScFieldId, s) =>
val result = r.intersectedReturnType.asTypeResult.orElse(f.`type`())
result.map { tp =>
if (isStableContext(tp) && f.isStable) {
r.fromType match {
case Some(fT) => ScProjectionType(fT, f)
case None => ScalaType.designator(f)
}
} else s(tp)
}.getOrElse(return result)
case ScalaResolveResult(typed: ScTypedDefinition, s) =>
typed.`type`() match {
case Right(tp) => s(tp)
case result => return result
}
case ScalaResolveResult(pack: PsiPackage, _) => ScalaType.designator(pack)
case ScalaResolveResult(clazz: ScClass, s) if clazz.isCase =>
val constructor =
clazz.constructor
.getOrElse(return Failure(ScalaBundle.message("case.class.has.no.primary.constructor")))
constructor.polymorphicType(s)
case ScalaResolveResult(clazz: ScTypeDefinition, s) if clazz.typeParameters.nonEmpty =>
s(ScParameterizedType(ScalaType.designator(clazz),
clazz.typeParameters.map(TypeParameterType(_))))
case ScalaResolveResult(clazz: PsiClass, _) => ScDesignatorType.static(clazz) //static Java class
case ScalaResolveResult(field: PsiField, s) =>
s(field.getType.toScType())
case ScalaResolveResult(c: ScNamedTupleComponent, s) =>
c.`type`() match {
case Right(tp) if c.is[ScNamedTupleExprComponent] =>
// even (x = "x").x is String
s(tp.widenIfLiteral)
case Right(tp) => s(tp)
case result => return result
}
case srr @ ScalaResolveResult(method: PsiMethod, s) =>
val returnType = srr.intersectedReturnType.orElse(
Option(method.containingClass).filter {
method.getName == "getClass" && _.getQualifiedName == "java.lang.Object"
}.flatMap { _ =>
val maybeReference = qualifier.orElse {
val result: Option[Typeable] = getContext match {
case infixExpr: ScInfixExpr if infixExpr.operation == this => Some(infixExpr.left)
case postfixExpr: ScPostfixExpr if postfixExpr.operation == this => Some(postfixExpr.operand)
case _ => ScalaPsiUtil.drvTemplate(this)
}
result
}
def getType(element: PsiNamedElement): Option[ScType] = Option(element).collect {
case pattern: ScBindingPattern => pattern
case fieldId: ScFieldId => fieldId
case parameter: ScParameter => parameter
}.flatMap {
_.`type`().toOption
}
def removeTypeDesignator(`type`: ScType): ScType = {
val maybeType = `type` match {
case ScDesignatorType(element) =>
getType(element)
case projectionType: ScProjectionType =>
getType(projectionType.actualElement).map(projectionType.actualSubst)
case _ => None
}
maybeType.map(removeTypeDesignator).getOrElse(`type`)
}
def convertQualifier(jlClass: PsiClass): ScType = {
val maybeType = maybeReference.flatMap {
_.`type`().toOption
}
val upperBound = maybeType.flatMap {
case ScThisType(clazz) => Some(ScDesignatorType(clazz))
case ScDesignatorType(_: ScObject) => None
case ScCompoundType(comps, _, _) => comps.headOption.map(removeTypeDesignator)
case tp => Some(tp).map(removeTypeDesignator)
}.getOrElse(Any)
val argument = ScExistentialArgument("_$1", Nil, Nothing, upperBound)
ScExistentialType(ScParameterizedType(ScDesignatorType(jlClass), Seq(argument)))
}
elementScope.getCachedClass("java.lang.Class")
.map(convertQualifier)
})
method
.methodTypeProvider(elementScope)
.polymorphicType(s, returnType)
case _ => return resolveFailure
}
val default =
if (unresolvedTypeParameters.nonEmpty)
inner match {
case ScTypePolymorphicType(internal, typeParams) =>
ScTypePolymorphicType(internal, unresolvedTypeParameters ++ typeParams)
case _ =>
ScTypePolymorphicType(inner, unresolvedTypeParameters)
}
else inner
val withUnresolvedTypeParams = qualifier match {
case Some(_: ScSuperReference) => default
case None => //infix, prefix and postfix
getContext match {
case sugar: ScSugarCallExpr if sugar.operation == this =>
sugar.getBaseExpr.getNonValueType() match {
case Right(ScTypePolymorphicType(_, typeParams)) =>
inner match {
case ScTypePolymorphicType(internal, typeParams2) =>
ScalaPsiUtil.removeBadBounds(ScTypePolymorphicType(internal, unresolvedTypeParameters ++ typeParams ++ typeParams2))
case _ =>
ScTypePolymorphicType(inner, unresolvedTypeParameters ++ typeParams)
}
case _ => default
}
case _ => default
}
case Some(qualifier) =>
qualifier.getNonValueType() match {
case Right(ScTypePolymorphicType(_, typeParams)) =>
inner match {
case ScTypePolymorphicType(internal, typeParams2) =>
return Right(ScalaPsiUtil.removeBadBounds(ScTypePolymorphicType(internal, unresolvedTypeParameters ++ typeParams ++ typeParams2)))
case _ =>
return Right(ScTypePolymorphicType(inner, unresolvedTypeParameters ++ typeParams))
}
case _ => default
}
}
Right(matchClauseSubst(withUnresolvedTypeParams))
}