bugfix: overloading resolution for typeof

This commit is contained in:
Araq 2011-09-27 00:27:51 +02:00
commit da6046dcba
7 changed files with 98 additions and 81 deletions

View file

@ -35,7 +35,7 @@ proc semStmtScope(c: PContext, n: PNode): PNode
type type
TExprFlag = enum TExprFlag = enum
efAllowType, efLValue, efWantIterator efAllowType, efLValue, efWantIterator, efInTypeof
TExprFlags = set[TExprFlag] TExprFlags = set[TExprFlag]
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode

View file

@ -35,6 +35,8 @@ proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
z.calleeSym = sym z.calleeSym = sym
matches(c, n, z) matches(c, n, z)
if z.state == csMatch: if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case x.state case x.state
of csEmpty, csNoMatch: x = z of csEmpty, csNoMatch: x = z
of csMatch: of csMatch:
@ -48,7 +50,7 @@ proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
# do not generate an error yet; the semantic checking will check for # do not generate an error yet; the semantic checking will check for
# an overloaded () operator # an overloaded () operator
elif y.state == csMatch and cmpCandidates(x, y) == 0 and elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym): not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch: if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch") InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [

View file

@ -445,13 +445,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
n.sons[i] = analyseIfAddressTaken(c, n.sons[i]) n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
var symflags = {skProc, skMethod, skConverter}
if efWantIterator in flags: if efWantIterator in flags:
# for ``type countup(1,3)``, see ``tests/ttoseq``. result = semDirectCall(c, n, {skIterator})
symflags = {skIterator} elif efInTypeOf in flags:
result = semDirectCall(c, n, symflags) # for ``type(countup(1,3))``, see ``tests/ttoseq``.
if result != nil: result = semDirectCall(c, n, {skIterator, skProc, skMethod, skConverter})
else:
result = semDirectCall(c, n, {skProc, skMethod, skConverter})
if result != nil:
if result.sons[0].kind != nkSym: if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects") InternalError("semDirectCallAnalyseEffects")
var callee = result.sons[0].sym var callee = result.sons[0].sym

View file

@ -625,23 +625,15 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s) if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
result = instGenericContainer(c, n, result) result = instGenericContainer(c, n, result)
proc FixupRemainingGenericInvokations(c: PContext, n: PNode,
typ: PType): PType =
if typ.kind == tyGenericInvokation:
nil
else:
result = typ
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil result = nil
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
case n.kind case n.kind
of nkEmpty: nil of nkEmpty: nil
of nkTypeOfExpr: of nkTypeOfExpr:
# for ``type countup(1,3)``, see ``tests/ttoseq``. # for ``type(countup(1,3))``, see ``tests/ttoseq``.
# XXX We should find a better solution.
checkSonsLen(n, 1) checkSonsLen(n, 1)
result = semExprWithType(c, n.sons[0], {efWantIterator}).typ result = semExprWithType(c, n.sons[0], {efInTypeof}).typ
of nkPar: of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected) else: GlobalError(n.info, errTypeExpected)

View file

@ -18,7 +18,7 @@ type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object TCandidate* {.final.} = object
exactMatches: int exactMatches*: int
subtypeMatches: int subtypeMatches: int
intConvMatches: int # conversions to int are not as expensive intConvMatches: int # conversions to int are not as expensive
convMatches: int convMatches: int

View file

@ -435,7 +435,7 @@ have no side-effect can be used in constant expressions too:
The rules for compile-time computability are: The rules for compile-time computability are:
1. Literals are compile-time computable. 1. Literals are compile-time computable.
2. Type conversions are compile-time computable. 2. Type conversions are compile-time computable.
3. Procedure calls of the form ``p(X)`` are compile-time computable if 3. Procedure calls of the form ``p(X)`` are compile-time computable if
``p`` is a proc without side-effects (see the `noSideEffect pragma`_ ``p`` is a proc without side-effects (see the `noSideEffect pragma`_
@ -1294,14 +1294,14 @@ algorithm (in pseudo-code) determines type equality:
Since types are graphs which can have cycles, the above algorithm needs an Since types are graphs which can have cycles, the above algorithm needs an
auxiliary set ``s`` to detect this case. auxiliary set ``s`` to detect this case.
Type equality modulo type distinction Type equality modulo type distinction
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following algorithm (in pseudo-code) determines whether two types The following algorithm (in pseudo-code) determines whether two types
are equal with no respect to ``distinct`` types. For brevity the cycle check are equal with no respect to ``distinct`` types. For brevity the cycle check
with an auxiliary set ``s`` is omitted: with an auxiliary set ``s`` is omitted:
.. code-block:: nimrod .. code-block:: nimrod
proc typeEqualsOrDistinct(a, b: PType): bool = proc typeEqualsOrDistinct(a, b: PType): bool =
@ -1324,15 +1324,15 @@ with an auxiliary set ``s`` is omitted:
for i in 0..a.tupleLen-1: for i in 0..a.tupleLen-1:
if not typeEqualsOrDistinct(a[i], b[i]): return false if not typeEqualsOrDistinct(a[i], b[i]): return false
result = true result = true
of distinct: of distinct:
result = typeEqualsOrDistinct(a.baseType, b.baseType) result = typeEqualsOrDistinct(a.baseType, b.baseType)
of object, enum: of object, enum:
result = a == b result = a == b
of proc: of proc:
result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and
typeEqualsOrDistinct(a.resultType, b.resultType) and typeEqualsOrDistinct(a.resultType, b.resultType) and
a.callingConvention == b.callingConvention a.callingConvention == b.callingConvention
elif a.kind == distinct: elif a.kind == distinct:
result = typeEqualsOrDistinct(a.baseType, b) result = typeEqualsOrDistinct(a.baseType, b)
elif b.kind == distinct: elif b.kind == distinct:
result = typeEqualsOrDistinct(a, b.baseType) result = typeEqualsOrDistinct(a, b.baseType)
@ -1413,10 +1413,10 @@ The convertible relation can be relaxed by a user-defined type
# you can use the explicit form too # you can use the explicit form too
x = chr.toInt x = chr.toInt
echo x # => 97 echo x # => 97
The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and
``typeEqualsOrDistinct(T, type(a))`` holds. ``typeEqualsOrDistinct(T, type(a))`` holds.
Assignment compatibility Assignment compatibility
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
@ -1460,7 +1460,8 @@ statements always have to be intended::
complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
| blockStmt | asmStmt | blockStmt | asmStmt
| procDecl | iteratorDecl | macroDecl | templateDecl | procDecl | iteratorDecl | macroDecl | templateDecl
| constSection | typeSection | whenStmt | varSection | constSection | letSection
| typeSection | whenStmt | varSection
@ -1474,26 +1475,26 @@ Syntax::
Example: Example:
.. code-block:: nimrod .. code-block:: nimrod
proc p(x, y: int): int {.optional.} = proc p(x, y: int): int {.optional.} =
return x + y return x + y
discard p(3, 4) # discard the return value of `p` discard p(3, 4) # discard the return value of `p`
The `discard`:idx: statement evaluates its expression for side-effects and The `discard`:idx: statement evaluates its expression for side-effects and
throws the expression's resulting value away. throws the expression's resulting value away.
Ignoring the return value of a procedure without using a discard statement is Ignoring the return value of a procedure without using a discard statement is
a static error. a static error.
The return value can be ignored implicitely if the called proc/iterator has The return value can be ignored implicitely if the called proc/iterator has
been declared with the `discardable`:idx: pragma: been declared with the `discardable`:idx: pragma:
.. code-block:: nimrod .. code-block:: nimrod
proc p(x, y: int): int {.discardable.} = proc p(x, y: int): int {.discardable.} =
return x + y return x + y
p(3, 4) # now valid p(3, 4) # now valid
Var statement Var statement
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
@ -2430,6 +2431,18 @@ be used to get the type of an expression:
var x = 0 var x = 0
var y: type(x) # y has type int var y: type(x) # y has type int
If ``type`` is used to determine the result type of a proc/iterator/converter
call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the
interpretation where ``c`` is an iterator is preferred over the
other interpretations:
.. code-block:: nimrod
import strutils
# strutils contains both a ``split`` proc and iterator, but since an
# an iterator is the preferred interpretation, `y` has the type ``string``:
var y: type("a b c".split)
Type constraints Type constraints
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
@ -2979,16 +2992,16 @@ only consist of an assembler statement.
error pragma error pragma
------------ ------------
The `error`:idx: pragma is used to make the compiler output an error message The `error`:idx: pragma is used to make the compiler output an error message
with the given content. Compilation does not necessarily abort after an error with the given content. Compilation does not necessarily abort after an error
though. though.
The ``error`` pragma can also be used to The ``error`` pragma can also be used to
annotate a symbol (like an iterator or proc). The *usage* of the symbol then annotate a symbol (like an iterator or proc). The *usage* of the symbol then
triggers a compile-time error. This is especially useful to rule out that some triggers a compile-time error. This is especially useful to rule out that some
operation is valid due to overloading and type conversions: operation is valid due to overloading and type conversions:
.. code-block:: nimrod .. code-block:: nimrod
## check that underlying int values are compared and not the pointers: ## check that underlying int values are compared and not the pointers:
proc `==`(x, y: ptr int): bool {.error.} proc `==`(x, y: ptr int): bool {.error.}
@ -3308,6 +3321,7 @@ Memory allocation requires no lock at all! This design easily scales to massive
multicore processors that will become the norm in the future. multicore processors that will become the norm in the future.
Thread pragma Thread pragma
------------- -------------
@ -3402,24 +3416,24 @@ The interaction between threads and exceptions is simple: A *handled* exception
in one thread cannot affect any other thread. However, an *unhandled* in one thread cannot affect any other thread. However, an *unhandled*
exception in one thread terminates the whole *process*! exception in one thread terminates the whole *process*!
Taint mode Taint mode
========== ==========
The Nimrod compiler and most parts of the standard library support The Nimrod compiler and most parts of the standard library support
a `taint mode`:idx:. Input strings are declared with the `TaintedString`:idx: a `taint mode`:idx:. Input strings are declared with the `TaintedString`:idx:
string type declared in the ``system`` module. string type declared in the ``system`` module.
If the taint mode is turned on (via the ``--taintMode:on`` command line If the taint mode is turned on (via the ``--taintMode:on`` command line
option) it is a distinct string type which helps to detect input option) it is a distinct string type which helps to detect input
validation errors: validation errors:
.. code-block:: nimrod .. code-block:: nimrod
echo "your name: " echo "your name: "
var name: TaintedString = stdin.readline var name: TaintedString = stdin.readline
# it is safe here to output the name without any input validation, so # it is safe here to output the name without any input validation, so
# we simply convert `name` to string to make the compiler happy: # we simply convert `name` to string to make the compiler happy:
echo "hi, ", name.string echo "hi, ", name.string
If the taint mode is turned off, ``TaintedString`` is simply an alias for If the taint mode is turned off, ``TaintedString`` is simply an alias for
``string``. ``string``.

View file

@ -10,3 +10,10 @@ template toSeq*(iter: expr): expr =
for x in items(toSeq(countup(2, 6))): for x in items(toSeq(countup(2, 6))):
stdout.write(x) stdout.write(x)
import strutils
var y: type("a b c".split)
y = "xzy"