重载解析

在调用 p(args) 中选择匹配最佳的例程 p 。 如果多个例程同样匹配,则在语义分析期间报告歧义。

args中的每个arg都需要匹配。参数可以匹配的方式有多种不同的类别。 设 f 是形式参数的类型, a 是参数的类型。

  • 准确匹配: a 和 f 是相同类型。
  • 字面匹配: a is an integer literal of value v and f is a signed or unsigned integer type and v is in f's range. Or: a is a floating point literal of value v and f is a floating point type and v is in f's range.
  • 泛型匹配: f 是泛型类型且 a 匹配, 例如 a 是 int 且 f 是泛型限制 (受限) 形参类型 (像 [T] 或 [T: int|char].
  • 子范围或子类型匹配: a is a range[T] and T matches f exactly. Or: a is a subtype of f.
  • 整数转换匹配: a 可转换为 f 且 f 和 a 是同样的整数或浮点类型。
  • 转换匹配: a 可能通过用户定义的转换器转换为 f 。 这些匹配类别具有优先级:完全匹配优于字面值匹配,并且优于通用匹配等。 在下面的 count(p, m) 计算 m 匹配过程 p 的匹配数。

A routine p matches better than a routine q if the following algorithm returns true:

  1. for each matching category m in ["exact match", "literal match",
  2. "generic match", "subtype match",
  3. "integral match", "conversion match"]:
  4. if count(p, m) > count(q, m): return true
  5. elif count(p, m) == count(q, m):
  6. discard "continue with next category m"
  7. else:
  8. return false
  9. return "ambiguous"

一些示例:

  1. proc takesInt(x: int) = echo "int"
  2. proc takesInt[T](x: T) = echo "T"
  3. proc takesInt(x: int16) = echo "int16"
  4.  
  5. takesInt(4) # "int"
  6. var x: int32
  7. takesInt(x) # "T"
  8. var y: int16
  9. takesInt(y) # "int16"
  10. var z: range[0..4] = 0
  11. takesInt(z) # "T"

如果算法返回 "歧义" 则执行进一步消歧: 如果参数 a 通过子类型关系匹配 p 的参数类型 fqg ,则考虑继承深度:

  1. type
  2. A = object of RootObj
  3. B = object of A
  4. C = object of B
  5.  
  6. proc p(obj: A) =
  7. echo "A"
  8.  
  9. proc p(obj: B) =
  10. echo "B"
  11.  
  12. var c = C()
  13. # not ambiguous, calls 'B', not 'A' since B is a subtype of A
  14. # but not vice versa:
  15. p(c)
  16.  
  17. proc pp(obj: A, obj2: B) = echo "A B"
  18. proc pp(obj: B, obj2: A) = echo "B A"
  19.  
  20. # but this is ambiguous:
  21. pp(c, c)

同样,对于通用匹配,匹配的结果中首选最特化的泛型类型:

  1. proc gen[T](x: ref ref T) = echo "ref ref T"
  2. proc gen[T](x: ref T) = echo "ref T"
  3. proc gen[T](x: T) = echo "T"
  4.  
  5. var ri: ref int
  6. gen(ri) # "ref T"