mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 22:13:29 +00:00
bugfix: overloading resolution for typeof
This commit is contained in:
@@ -35,7 +35,7 @@ proc semStmtScope(c: PContext, n: PNode): PNode
|
||||
|
||||
type
|
||||
TExprFlag = enum
|
||||
efAllowType, efLValue, efWantIterator
|
||||
efAllowType, efLValue, efWantIterator, efInTypeof
|
||||
TExprFlags = set[TExprFlag]
|
||||
|
||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
|
||||
@@ -35,6 +35,8 @@ proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
|
||||
z.calleeSym = sym
|
||||
matches(c, n, z)
|
||||
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
|
||||
of csEmpty, csNoMatch: x = z
|
||||
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
|
||||
# an overloaded () operator
|
||||
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:
|
||||
InternalError(n.info, "x.state is not csMatch")
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
|
||||
@@ -445,13 +445,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
|
||||
|
||||
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
var symflags = {skProc, skMethod, skConverter}
|
||||
flags: TExprFlags): PNode =
|
||||
if efWantIterator in flags:
|
||||
# for ``type countup(1,3)``, see ``tests/ttoseq``.
|
||||
symflags = {skIterator}
|
||||
result = semDirectCall(c, n, symflags)
|
||||
if result != nil:
|
||||
result = semDirectCall(c, n, {skIterator})
|
||||
elif efInTypeOf in flags:
|
||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||
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:
|
||||
InternalError("semDirectCallAnalyseEffects")
|
||||
var callee = result.sons[0].sym
|
||||
|
||||
@@ -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)
|
||||
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 =
|
||||
result = nil
|
||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||
case n.kind
|
||||
of nkEmpty: nil
|
||||
of nkTypeOfExpr:
|
||||
# for ``type countup(1,3)``, see ``tests/ttoseq``.
|
||||
# XXX We should find a better solution.
|
||||
of nkTypeOfExpr:
|
||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||
checkSonsLen(n, 1)
|
||||
result = semExprWithType(c, n.sons[0], {efWantIterator}).typ
|
||||
result = semExprWithType(c, n.sons[0], {efInTypeof}).typ
|
||||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else: GlobalError(n.info, errTypeExpected)
|
||||
|
||||
@@ -18,7 +18,7 @@ type
|
||||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
TCandidate* {.final.} = object
|
||||
exactMatches: int
|
||||
exactMatches*: int
|
||||
subtypeMatches: int
|
||||
intConvMatches: int # conversions to int are not as expensive
|
||||
convMatches: int
|
||||
|
||||
136
doc/manual.txt
136
doc/manual.txt
@@ -435,7 +435,7 @@ have no side-effect can be used in constant expressions too:
|
||||
|
||||
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.
|
||||
3. Procedure calls of the form ``p(X)`` are compile-time computable if
|
||||
``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
|
||||
auxiliary set ``s`` to detect this case.
|
||||
|
||||
|
||||
|
||||
|
||||
Type equality modulo type distinction
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following algorithm (in pseudo-code) determines whether two types
|
||||
are equal with no respect to ``distinct`` types. For brevity the cycle check
|
||||
with an auxiliary set ``s`` is omitted:
|
||||
The following algorithm (in pseudo-code) determines whether two types
|
||||
are equal with no respect to ``distinct`` types. For brevity the cycle check
|
||||
with an auxiliary set ``s`` is omitted:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc typeEqualsOrDistinct(a, b: PType): bool =
|
||||
@@ -1324,15 +1324,15 @@ with an auxiliary set ``s`` is omitted:
|
||||
for i in 0..a.tupleLen-1:
|
||||
if not typeEqualsOrDistinct(a[i], b[i]): return false
|
||||
result = true
|
||||
of distinct:
|
||||
result = typeEqualsOrDistinct(a.baseType, b.baseType)
|
||||
of distinct:
|
||||
result = typeEqualsOrDistinct(a.baseType, b.baseType)
|
||||
of object, enum:
|
||||
result = a == b
|
||||
of proc:
|
||||
result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and
|
||||
typeEqualsOrDistinct(a.resultType, b.resultType) and
|
||||
a.callingConvention == b.callingConvention
|
||||
elif a.kind == distinct:
|
||||
a.callingConvention == b.callingConvention
|
||||
elif a.kind == distinct:
|
||||
result = typeEqualsOrDistinct(a.baseType, b)
|
||||
elif b.kind == distinct:
|
||||
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
|
||||
x = chr.toInt
|
||||
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.
|
||||
|
||||
|
||||
|
||||
Assignment compatibility
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1460,7 +1460,8 @@ statements always have to be intended::
|
||||
complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
|
||||
| blockStmt | asmStmt
|
||||
| procDecl | iteratorDecl | macroDecl | templateDecl
|
||||
| constSection | typeSection | whenStmt | varSection
|
||||
| constSection | letSection
|
||||
| typeSection | whenStmt | varSection
|
||||
|
||||
|
||||
|
||||
@@ -1474,26 +1475,26 @@ Syntax::
|
||||
Example:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc p(x, y: int): int {.optional.} =
|
||||
return x + y
|
||||
proc p(x, y: int): int {.optional.} =
|
||||
return x + y
|
||||
|
||||
discard p(3, 4) # discard the return value of `p`
|
||||
|
||||
The `discard`:idx: statement evaluates its expression for side-effects and
|
||||
throws the expression's resulting value away.
|
||||
|
||||
Ignoring the return value of a procedure without using a discard statement is
|
||||
a static error.
|
||||
|
||||
The return value can be ignored implicitely if the called proc/iterator has
|
||||
been declared with the `discardable`:idx: pragma:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc p(x, y: int): int {.discardable.} =
|
||||
return x + y
|
||||
|
||||
p(3, 4) # now valid
|
||||
|
||||
throws the expression's resulting value away.
|
||||
|
||||
Ignoring the return value of a procedure without using a discard statement is
|
||||
a static error.
|
||||
|
||||
The return value can be ignored implicitely if the called proc/iterator has
|
||||
been declared with the `discardable`:idx: pragma:
|
||||
|
||||
.. code-block:: nimrod
|
||||
proc p(x, y: int): int {.discardable.} =
|
||||
return x + y
|
||||
|
||||
p(3, 4) # now valid
|
||||
|
||||
|
||||
Var statement
|
||||
~~~~~~~~~~~~~
|
||||
@@ -2430,6 +2431,18 @@ be used to get the type of an expression:
|
||||
var x = 0
|
||||
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
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -2979,16 +2992,16 @@ only consist of an assembler statement.
|
||||
error pragma
|
||||
------------
|
||||
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
|
||||
though.
|
||||
|
||||
The ``error`` pragma can also be used to
|
||||
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
|
||||
operation is valid due to overloading and type conversions:
|
||||
|
||||
.. code-block:: nimrod
|
||||
## check that underlying int values are compared and not the pointers:
|
||||
with the given content. Compilation does not necessarily abort after an error
|
||||
though.
|
||||
|
||||
The ``error`` pragma can also be used to
|
||||
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
|
||||
operation is valid due to overloading and type conversions:
|
||||
|
||||
.. code-block:: nimrod
|
||||
## check that underlying int values are compared and not the pointers:
|
||||
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.
|
||||
|
||||
|
||||
|
||||
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*
|
||||
exception in one thread terminates the whole *process*!
|
||||
|
||||
Taint mode
|
||||
==========
|
||||
|
||||
The Nimrod compiler and most parts of the standard library support
|
||||
a `taint mode`:idx:. Input strings are declared with the `TaintedString`:idx:
|
||||
string type declared in the ``system`` module.
|
||||
|
||||
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
|
||||
validation errors:
|
||||
|
||||
.. code-block:: nimrod
|
||||
echo "your name: "
|
||||
var name: TaintedString = stdin.readline
|
||||
# it is safe here to output the name without any input validation, so
|
||||
# we simply convert `name` to string to make the compiler happy:
|
||||
echo "hi, ", name.string
|
||||
|
||||
If the taint mode is turned off, ``TaintedString`` is simply an alias for
|
||||
``string``.
|
||||
|
||||
Taint mode
|
||||
==========
|
||||
|
||||
The Nimrod compiler and most parts of the standard library support
|
||||
a `taint mode`:idx:. Input strings are declared with the `TaintedString`:idx:
|
||||
string type declared in the ``system`` module.
|
||||
|
||||
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
|
||||
validation errors:
|
||||
|
||||
.. code-block:: nimrod
|
||||
echo "your name: "
|
||||
var name: TaintedString = stdin.readline
|
||||
# it is safe here to output the name without any input validation, so
|
||||
# we simply convert `name` to string to make the compiler happy:
|
||||
echo "hi, ", name.string
|
||||
|
||||
If the taint mode is turned off, ``TaintedString`` is simply an alias for
|
||||
``string``.
|
||||
|
||||
|
||||
@@ -10,3 +10,10 @@ template toSeq*(iter: expr): expr =
|
||||
for x in items(toSeq(countup(2, 6))):
|
||||
stdout.write(x)
|
||||
|
||||
import strutils
|
||||
|
||||
var y: type("a b c".split)
|
||||
y = "xzy"
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user