aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Signature.scala
blob: 4699cecf24216de7ce62b1a5da5af01357e659c1 (plain) (tree)
1
2
3
4
5
6
7
8


                        
                                               
                          
 

                               

















                                                                                                      





                                                                                     
   
                                                                   
                    
 







                                                                   


                                                                                             
 




                                                                                    
                                                                                




                                                                                                    
                                                        
                                                                                            
                                                       
                                                                                               
                          
                                                                         
     
                                                                              
                               



                                                                                           



                                                                                 


                                                                                   

                                                                           
 
                                                                              
                                                                                    




                                                                                      



                  




                        


                                                                    
                                                   
 


                                                                            

                                                                                   

                                                                                    
                                           
   
 
package dotty.tools.dotc
package core

import Names._, Types._, Contexts._, StdNames._
import TypeErasure.sigName

import scala.annotation.tailrec

/** The signature of a denotation.
 *  Overloaded denotations with the same name are distinguished by
 *  their signatures. A signature of a method (of type PolyType,MethodType, or ExprType) is
 *  composed of a list of signature names, one for each parameter type, plus a signature for
 *  the result type. Methods are uncurried before taking their signatures.
 *  The signature name of a type is the fully qualified name of the type symbol of the type's erasure.
 *
 *  For instance a definition
 *
 *      def f(x: Int)(y: List[String]): String
 *
 *  would have signature
 *
 *      Signature(
 *        List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName),
 *        "scala.String".toTypeName)
 *
 *  The signatures of non-method types are always `NotAMethod`.
 *
 *  There are three kinds of "missing" parts of signatures:
 *
 *   - tpnme.EMPTY          Result type marker for NotAMethod and OverloadedSignature
 *   - tpnme.WILDCARD       Arises from a Wildcard or error type
 *   - tpnme.Uninstantiated Arises from an uninstantiated type variable
 */
case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
  import Signature._

/* FIXME does not compile under dotty, we get a missing param error
  def checkUnqual(name: TypeName) = name mapParts { part =>
    assert(!part.contains('.'), name)
    part
  }
  paramsSig.foreach(checkUnqual)
  checkUnqual(resSig)
*/
  /** Two names are consistent if they are the same or one of them is tpnme.Uninstantiated */
  private def consistent(name1: TypeName, name2: TypeName) =
    name1 == name2 || name1 == tpnme.Uninstantiated || name2 == tpnme.Uninstantiated

  /** Does this signature coincide with that signature on their parameter parts?
   *  This is the case if all parameter names are _consistent_, i.e. they are either
   *  equal or on of them is tpnme.Uninstantiated.
   */
  final def consistentParams(that: Signature): Boolean = {
    @tailrec def loop(names1: List[TypeName], names2: List[TypeName]): Boolean =
      if (names1.isEmpty) names2.isEmpty
      else names2.nonEmpty && consistent(names1.head, names2.head) && loop(names1.tail, names2.tail)
    loop(this.paramsSig, that.paramsSig)
  }

  /** The degree to which this signature matches `that`.
   *  If parameter names are consistent and result types names match (i.e. they are the same
   *  or one is a wildcard), the result is `FullMatch`.
   *  If only the parameter names are consistent, the result is `ParamMatch` before erasure and
   *  `NoMatch` otherwise.
   *  If the parameters are inconsistent, the result is always `NoMatch`.
   */
  final def matchDegree(that: Signature)(implicit ctx: Context): MatchDegree =
    if (consistentParams(that))
      if (resSig == that.resSig || isWildcard(resSig) || isWildcard(that.resSig)) FullMatch
      else if (!ctx.erasedTypes) ParamMatch
      else NoMatch
    else NoMatch

  /** name.toString == "" or name.toString == "_" */
  private def isWildcard(name: TypeName) = name.isEmpty || name == tpnme.WILDCARD

  /** Construct a signature by prepending the signature names of the given `params`
   *  to the parameter part of this signature.
   */
  def prepend(params: List[Type], isJava: Boolean)(implicit ctx: Context) =
    Signature((params.map(sigName(_, isJava))) ++ paramsSig, resSig)

  /** A signature is under-defined if its paramsSig part contains at least one
   *  `tpnme.Uninstantiated`. Under-defined signatures arise when taking a signature
   *  of a type that still contains uninstantiated type variables. They are eliminated
   *  by `fixSignature` in `PostTyper`.
   */
  def isUnderDefined(implicit ctx: Context) =
    paramsSig.contains(tpnme.Uninstantiated) || resSig == tpnme.Uninstantiated
}

object Signature {

  type MatchDegree = Int
  val NoMatch = 0
  val ParamMatch = 1
  val FullMatch = 2

  /** The signature of everything that's not a method, i.e. that has
   *  a type different from PolyType, MethodType, or ExprType.
   */
  val NotAMethod = Signature(List(), EmptyTypeName)

  /** The signature of an overloaded denotation.
   */
  val OverloadedSignature = Signature(List(tpnme.OVERLOADED), EmptyTypeName)

  /** The signature of a method with no parameters and result type `resultType`. */
  def apply(resultType: Type, isJava: Boolean)(implicit ctx: Context): Signature = {
    assert(!resultType.isInstanceOf[ExprType])
    apply(Nil, sigName(resultType, isJava))
  }
}