1
1
package dotty .tools .dotc
2
2
package core
3
3
4
+ import scala .annotation .tailrec
5
+
4
6
import Names ._ , Types ._ , Contexts ._ , StdNames ._ , Decorators ._
5
7
import TypeErasure .sigName
6
-
7
- import scala .annotation .tailrec
8
+ import Signature ._
8
9
9
10
/** The signature of a denotation.
10
- * Overloaded denotations with the same name are distinguished by
11
- * their signatures. A signature of a method (of type PolyType,MethodType, or ExprType) is
12
- * composed of a list of signature names, one for each parameter type, plus a signature for
13
- * the result type. Methods are uncurried before taking their signatures.
14
- * The signature name of a type is the fully qualified name of the type symbol of the type's erasure.
11
+ *
12
+ * Same-named denotations with different signatures are considered to be
13
+ * overloads, see `SingleDenotation#matches` for more details.
14
+ *
15
+ * A _method signature_ (a value of type `Signature`, excluding `NotAMethod`
16
+ * and `OverloadedSignature`) is composed of a list of _parameter signatures_,
17
+ * plus a _type signature_ for the final result type.
18
+ *
19
+ * A _parameter signature_ (a value of type `ParamSig`) is either an integer,
20
+ * representing the number of type parameters in a type parameter section, or
21
+ * the _type signature_ of a term parameter.
22
+ *
23
+ * A _type signature_ is the fully qualified name of the type symbol of the
24
+ * type's erasure.
15
25
*
16
26
* For instance a definition
17
27
*
18
- * def f(x: Int)(y: List[String ]): String
28
+ * def f[T, S] (x: Int)(y: List[T ]): S
19
29
*
20
30
* would have signature
21
31
*
22
32
* Signature(
23
- * List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName),
24
- * "scala.String".toTypeName)
33
+ * List(2, "scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName),
34
+ * "java.lang.Object".toTypeName)
35
+ *
36
+ * Note that `paramsSig` has one entry for *a whole type parameter section* but
37
+ * one entry *for each term parameter* (currently, methods in Dotty can only
38
+ * have one type parameter section but this encoding leaves the door open for
39
+ * supporting multiple sections).
25
40
*
26
41
* The signatures of non-method types are always `NotAMethod`.
27
42
*
@@ -31,19 +46,18 @@ import scala.annotation.tailrec
31
46
* - tpnme.WILDCARD Arises from a Wildcard or error type
32
47
* - tpnme.Uninstantiated Arises from an uninstantiated type variable
33
48
*/
34
- case class Signature (paramsSig : List [TypeName ], resSig : TypeName ) {
35
- import Signature ._
49
+ case class Signature (paramsSig : List [ParamSig ], resSig : TypeName ) {
36
50
37
51
/** Two names are consistent if they are the same or one of them is tpnme.Uninstantiated */
38
- private def consistent (name1 : TypeName , name2 : TypeName ) =
52
+ private def consistent (name1 : ParamSig , name2 : ParamSig ) =
39
53
name1 == name2 || name1 == tpnme.Uninstantiated || name2 == tpnme.Uninstantiated
40
54
41
55
/** Does this signature coincide with that signature on their parameter parts?
42
- * This is the case if all parameter names are _consistent_, i.e. they are either
56
+ * This is the case if all parameter signatures are _consistent_, i.e. they are either
43
57
* equal or on of them is tpnme.Uninstantiated.
44
58
*/
45
59
final def consistentParams (that : Signature )(implicit ctx : Context ): Boolean = {
46
- @ tailrec def loop (names1 : List [TypeName ], names2 : List [TypeName ]): Boolean =
60
+ @ tailrec def loop (names1 : List [ParamSig ], names2 : List [ParamSig ]): Boolean =
47
61
if (names1.isEmpty) names2.isEmpty
48
62
else ! names2.isEmpty && consistent(names1.head, names2.head) && loop(names1.tail, names2.tail)
49
63
if (ctx.erasedTypes && (this == NotAMethod ) != (that == NotAMethod ))
@@ -56,22 +70,23 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
56
70
57
71
/** `that` signature, but keeping all corresponding parts of `this` signature. */
58
72
final def updateWith (that : Signature ): Signature = {
59
- def update (name1 : TypeName , name2 : TypeName ): TypeName =
73
+ def update [ T <: ParamSig ] (name1 : T , name2 : T ): T =
60
74
if (consistent(name1, name2)) name1 else name2
61
75
if (this == that) this
62
76
else if (! this .paramsSig.hasSameLengthAs(that.paramsSig)) that
63
77
else {
64
78
val mapped = Signature (
65
- this .paramsSig.zipWithConserve(that.paramsSig)(update),
79
+ // DOTTY: we shouldn't have to explicitly pass a type argument to `update`
80
+ this .paramsSig.zipWithConserve(that.paramsSig)(update[ParamSig ]),
66
81
update(this .resSig, that.resSig))
67
82
if (mapped == this ) this else mapped
68
83
}
69
84
}
70
85
71
86
/** The degree to which this signature matches `that`.
72
- * If parameter names are consistent and result types names match (i.e. they are the same
87
+ * If parameter signatures are consistent and result types names match (i.e. they are the same
73
88
* or one is a wildcard), the result is `FullMatch`.
74
- * If only the parameter names are consistent, the result is ` ParamMatch` before erasure and
89
+ * If only the parameter signatures are consistent, the result ParamMatch` before erasure and
75
90
* `NoMatch` otherwise.
76
91
* If the parameters are inconsistent, the result is always `NoMatch`.
77
92
*/
@@ -94,8 +109,16 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
94
109
*
95
110
* Like Signature#apply, the result is only cacheable if `isUnderDefined == false`.
96
111
*/
97
- def prepend (params : List [Type ], isJava : Boolean )(implicit ctx : Context ): Signature =
98
- Signature (params.map(p => sigName(p, isJava)) ++ paramsSig, resSig)
112
+ def prependTermParams (params : List [Type ], isJava : Boolean )(implicit ctx : Context ): Signature =
113
+ Signature (params.map(p => sigName(p, isJava)) ::: paramsSig, resSig)
114
+
115
+ /** Construct a signature by prepending the length of a type parameter section
116
+ * to the parameter part of this signature.
117
+ *
118
+ * Like Signature#apply, the result is only cacheable if `isUnderDefined == false`.
119
+ */
120
+ def prependTypeParams (typeParamSigsSectionLength : Int )(implicit ctx : Context ): Signature =
121
+ Signature (typeParamSigsSectionLength :: paramsSig, resSig)
99
122
100
123
/** A signature is under-defined if its paramsSig part contains at least one
101
124
* `tpnme.Uninstantiated`. Under-defined signatures arise when taking a signature
@@ -106,6 +129,10 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
106
129
}
107
130
108
131
object Signature {
132
+ /** A parameter signature, see the documentation of `Signature` for more information. */
133
+ type ParamSig = TypeName | Int
134
+ // Erasure means that our Ints will be boxed, but Integer#valueOf caches
135
+ // small values, so the performance hit should be minimal.
109
136
110
137
enum MatchDegree {
111
138
case NoMatch , ParamMatch , FullMatch
0 commit comments