bugfix: type converter that converts to bool in 'if' context
This commit is contained in:
parent
220dd54acf
commit
032599c156
11 changed files with 77 additions and 25 deletions
|
|
@ -88,6 +88,11 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.
|
||||||
## the object! This means that for each object of type `T` the finalizer
|
## the object! This means that for each object of type `T` the finalizer
|
||||||
## will be called!
|
## will be called!
|
||||||
|
|
||||||
|
proc reset*(obj: var T) {.magic: "Reset", noSideEffect.}
|
||||||
|
proc reset*(obj: ref T) {.noSideEffect.} = reset(obj^)
|
||||||
|
## resets an object `obj` to its initial (binary zero) value. This needs to
|
||||||
|
## be called before any possible `object branch transition`:idx:.
|
||||||
|
|
||||||
# for low and high the return type T may not be correct, but
|
# for low and high the return type T may not be correct, but
|
||||||
# we handle that with compiler magic in SemLowHigh()
|
# we handle that with compiler magic in SemLowHigh()
|
||||||
proc high*[T](x: T): T {.magic: "High", noSideEffect.}
|
proc high*[T](x: T): T {.magic: "High", noSideEffect.}
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,7 @@ proc evalAsgn(c: PEvalContext, n: PNode): PNode =
|
||||||
var x = result
|
var x = result
|
||||||
result = evalAux(c, n.sons[1], {})
|
result = evalAux(c, n.sons[1], {})
|
||||||
if isSpecial(result): return
|
if isSpecial(result): return
|
||||||
|
when defined(system.reset): reset(x)
|
||||||
x.kind = result.kind
|
x.kind = result.kind
|
||||||
x.typ = result.typ
|
x.typ = result.typ
|
||||||
case x.kind
|
case x.kind
|
||||||
|
|
|
||||||
30
rod/sem.nim
30
rod/sem.nim
|
|
@ -115,16 +115,36 @@ proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
|
||||||
|
|
||||||
include seminst, semcall
|
include seminst, semcall
|
||||||
|
|
||||||
proc CheckBool(t: PNode) =
|
|
||||||
if (t.Typ == nil) or
|
|
||||||
(skipTypes(t.Typ, {tyGenericInst, tyVar, tyOrdinal}).kind != tyBool):
|
|
||||||
LocalError(t.Info, errExprMustBeBool)
|
|
||||||
|
|
||||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||||
GlobalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
GlobalError(n.Info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||||
typeToString(actual) & ") " &
|
typeToString(actual) & ") " &
|
||||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||||
|
|
||||||
|
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||||
|
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
||||||
|
if result == nil:
|
||||||
|
#debug(arg)
|
||||||
|
typeMismatch(arg, formal, arg.typ)
|
||||||
|
|
||||||
|
proc forceBool(c: PContext, n: PNode): PNode =
|
||||||
|
result = fitNode(c, getSysType(tyBool), n)
|
||||||
|
if result == nil: result = n
|
||||||
|
when false:
|
||||||
|
result = t
|
||||||
|
if (t.Typ == nil) or
|
||||||
|
(skipTypes(t.Typ, {tyGenericInst, tyVar, tyOrdinal}).kind != tyBool):
|
||||||
|
var a = ConvertTo(c, getSysType(tyBool), t)
|
||||||
|
if a != nil: result = a
|
||||||
|
else: LocalError(t.Info, errExprMustBeBool)
|
||||||
|
|
||||||
|
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||||
|
result = fitNode(c, getSysType(tyBool), semExprWithType(c, n))
|
||||||
|
if result == nil:
|
||||||
|
GlobalError(n.info, errConstExprExpected)
|
||||||
|
return
|
||||||
|
result = getConstExpr(c.module, result)
|
||||||
|
if result == nil: GlobalError(n.info, errConstExprExpected)
|
||||||
|
|
||||||
include semtypes, semexprs, semgnrc, semstmts
|
include semtypes, semexprs, semgnrc, semstmts
|
||||||
|
|
||||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -792,8 +792,7 @@ proc semIfExpr(c: PContext, n: PNode): PNode =
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifExpr:
|
of nkElifExpr:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
it.sons[0] = semExprWithType(c, it.sons[0])
|
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
|
||||||
checkBool(it.sons[0])
|
|
||||||
it.sons[1] = semExprWithType(c, it.sons[1])
|
it.sons[1] = semExprWithType(c, it.sons[1])
|
||||||
if typ == nil: typ = it.sons[1].typ
|
if typ == nil: typ = it.sons[1].typ
|
||||||
else: it.sons[1] = fitNode(c, typ, it.sons[1])
|
else: it.sons[1] = fitNode(c, typ, it.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@ proc semWhen(c: PContext, n: PNode): PNode =
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
var e = semConstExpr(c, it.sons[0])
|
var e = semConstBoolExpr(c, it.sons[0])
|
||||||
checkBool(e)
|
|
||||||
if (e.kind != nkIntLit): InternalError(n.info, "semWhen")
|
if (e.kind != nkIntLit): InternalError(n.info, "semWhen")
|
||||||
if (e.intVal != 0) and (result == nil):
|
if (e.intVal != 0) and (result == nil):
|
||||||
result = semStmt(c, it.sons[1]) # do not open a new scope!
|
result = semStmt(c, it.sons[1]) # do not open a new scope!
|
||||||
|
|
@ -63,8 +62,7 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
it.sons[0] = semExprWithType(c, it.sons[0])
|
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
|
||||||
checkBool(it.sons[0])
|
|
||||||
it.sons[1] = semStmt(c, it.sons[1])
|
it.sons[1] = semStmt(c, it.sons[1])
|
||||||
closeScope(c.tab)
|
closeScope(c.tab)
|
||||||
of nkElse:
|
of nkElse:
|
||||||
|
|
@ -121,8 +119,7 @@ proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
|
||||||
CheckBool(n.sons[0])
|
|
||||||
inc(c.p.nestedLoopCounter)
|
inc(c.p.nestedLoopCounter)
|
||||||
n.sons[1] = semStmt(c, n.sons[1])
|
n.sons[1] = semStmt(c, n.sons[1])
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
|
|
@ -162,8 +159,7 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
chckCovered = false
|
chckCovered = false
|
||||||
checkSonsLen(x, 2)
|
checkSonsLen(x, 2)
|
||||||
x.sons[0] = semExprWithType(c, x.sons[0])
|
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
|
||||||
checkBool(x.sons[0])
|
|
||||||
x.sons[1] = semStmtScope(c, x.sons[1])
|
x.sons[1] = semStmtScope(c, x.sons[1])
|
||||||
of nkElse:
|
of nkElse:
|
||||||
chckCovered = false
|
chckCovered = false
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,6 @@
|
||||||
|
|
||||||
# this module does the semantic checking of type declarations
|
# this module does the semantic checking of type declarations
|
||||||
|
|
||||||
proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
|
||||||
result = IndexTypesMatch(c, formal, arg.typ, arg)
|
|
||||||
if result == nil:
|
|
||||||
#debug(arg)
|
|
||||||
typeMismatch(arg, formal, arg.typ)
|
|
||||||
|
|
||||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
result = newTypeS(kind, c)
|
result = newTypeS(kind, c)
|
||||||
|
|
@ -355,8 +349,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||||
case it.kind
|
case it.kind
|
||||||
of nkElifBranch:
|
of nkElifBranch:
|
||||||
checkSonsLen(it, 2)
|
checkSonsLen(it, 2)
|
||||||
e = semConstExpr(c, it.sons[0])
|
e = semConstBoolExpr(c, it.sons[0])
|
||||||
checkBool(e)
|
|
||||||
if (e.kind != nkIntLit): InternalError(e.info, "semRecordNodeAux")
|
if (e.kind != nkIntLit): InternalError(e.info, "semRecordNodeAux")
|
||||||
if (e.intVal != 0) and (branch == nil): branch = it.sons[1]
|
if (e.intVal != 0) and (branch == nil): branch = it.sons[1]
|
||||||
of nkElse:
|
of nkElse:
|
||||||
|
|
|
||||||
|
|
@ -461,6 +461,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
var dest = c.converters[i].typ.sons[0]
|
var dest = c.converters[i].typ.sons[0]
|
||||||
if (typeRel(m.bindings, f, dest) == isEqual) and
|
if (typeRel(m.bindings, f, dest) == isEqual) and
|
||||||
(typeRel(m.bindings, src, a) == isEqual):
|
(typeRel(m.bindings, src, a) == isEqual):
|
||||||
|
markUsed(arg, c.converters[i])
|
||||||
var s = newSymNode(c.converters[i])
|
var s = newSymNode(c.converters[i])
|
||||||
s.typ = c.converters[i].typ
|
s.typ = c.converters[i].typ
|
||||||
s.info = arg.info
|
s.info = arg.info
|
||||||
|
|
@ -564,6 +565,11 @@ proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||||
initCandidate(m, f)
|
initCandidate(m, f)
|
||||||
result = paramTypesMatch(c, m, f, a, arg)
|
result = paramTypesMatch(c, m, f, a, arg)
|
||||||
|
|
||||||
|
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
|
||||||
|
var m: TCandidate
|
||||||
|
initCandidate(m, f)
|
||||||
|
result = paramTypesMatch(c, m, f, n.typ, n)
|
||||||
|
|
||||||
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(m, f)
|
initCandidate(m, f)
|
||||||
|
|
|
||||||
11
tests/accept/compile/tcan_alias_generic.nim
Normal file
11
tests/accept/compile/tcan_alias_generic.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
##
|
||||||
|
## can_alias_generic Nimrod Module
|
||||||
|
##
|
||||||
|
## Created by Eric Doughty-Papassideris on 2011-02-16.
|
||||||
|
## Copyright (c) 2011 FWA. All rights reserved.
|
||||||
|
|
||||||
|
type
|
||||||
|
TGen[T] = object
|
||||||
|
TGen2[T] = TGen[T]
|
||||||
|
|
||||||
|
|
||||||
11
tests/accept/compile/tcan_alias_specialised_generic.nim
Normal file
11
tests/accept/compile/tcan_alias_specialised_generic.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
##
|
||||||
|
## can_alias_specialised_generic Nimrod Module
|
||||||
|
##
|
||||||
|
## Created by Eric Doughty-Papassideris on 2011-02-16.
|
||||||
|
## Copyright (c) 2011 FWA. All rights reserved.
|
||||||
|
|
||||||
|
type
|
||||||
|
TGen[T] = object
|
||||||
|
TSpef = TGen[string]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
converter p(i: int): bool = return i != 0
|
converter p(i: int): bool = return i != 0
|
||||||
|
|
||||||
if 0:
|
if 1:
|
||||||
echo "foo"
|
echo if 4: "foo" else: "barr"
|
||||||
|
while 0:
|
||||||
|
echo "bar"
|
||||||
|
|
||||||
|
|
|
||||||
8
tests/reject/tno_int_in_bool_context.nim
Normal file
8
tests/reject/tno_int_in_bool_context.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
discard """
|
||||||
|
line: 6
|
||||||
|
errormsg: "Error: type mismatch: got (int) but expected 'bool'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
if 1:
|
||||||
|
echo "wtf?"
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue