fixed dot operator recursive loop & macro suggest (#16922)
* basic stability improvements; refs nimsuggest * fixed dot operator recursive loop & macro suggest * hacky fix for run away dot operator sem check Committing this mostly to make the issue more clear. Perhaps get better feedback. * semExprWithType seems like a better place to check * fixed error messages const case expressions * Clean-up test * stopped the dot operator madness No longer get infinite recursion when seming broken code with a dot operator macro like in jsffi. Co-authored-by: Araq <rumpf_a@web.de>
This commit is contained in:
parent
b68ecc82cb
commit
260a5dacb7
8 changed files with 51 additions and 24 deletions
|
|
@ -66,10 +66,17 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
rejectEmptyNode(n)
|
rejectEmptyNode(n)
|
||||||
result = semExpr(c, n, flags+{efWantValue})
|
result = semExpr(c, n, flags+{efWantValue})
|
||||||
if result.kind == nkEmpty:
|
|
||||||
|
let
|
||||||
|
isEmpty = result.kind == nkEmpty
|
||||||
|
isTypeError = result.typ != nil and result.typ.kind == tyError
|
||||||
|
|
||||||
|
if isEmpty or isTypeError:
|
||||||
# bug #12741, redundant error messages are the lesser evil here:
|
# bug #12741, redundant error messages are the lesser evil here:
|
||||||
localError(c.config, n.info, errExprXHasNoType %
|
localError(c.config, n.info, errExprXHasNoType %
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
||||||
|
if isEmpty:
|
||||||
# do not produce another redundant error message:
|
# do not produce another redundant error message:
|
||||||
result = errorNode(c, n)
|
result = errorNode(c, n)
|
||||||
|
|
||||||
|
|
@ -79,6 +86,9 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
localError(c.config, n.info, errExprXHasNoType %
|
localError(c.config, n.info, errExprXHasNoType %
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
|
elif result.typ.kind == tyError:
|
||||||
|
# associates the type error to the current owner
|
||||||
|
result.typ = errorType(c)
|
||||||
else:
|
else:
|
||||||
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
|
||||||
|
|
||||||
|
|
@ -887,6 +897,9 @@ proc setGenericParams(c: PContext, n: PNode) =
|
||||||
n[i].typ = semTypeNode(c, n[i], nil)
|
n[i].typ = semTypeNode(c, n[i], nil)
|
||||||
|
|
||||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
|
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
|
||||||
|
return errorNode(c, n)
|
||||||
|
|
||||||
result = n
|
result = n
|
||||||
let callee = result[0].sym
|
let callee = result[0].sym
|
||||||
case callee.kind
|
case callee.kind
|
||||||
|
|
@ -1368,6 +1381,9 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
return tryReadingTypeField(c, n, i, ty.base)
|
return tryReadingTypeField(c, n, i, ty.base)
|
||||||
elif isTypeExpr(n.sons[0]):
|
elif isTypeExpr(n.sons[0]):
|
||||||
return tryReadingTypeField(c, n, i, ty)
|
return tryReadingTypeField(c, n, i, ty)
|
||||||
|
elif ty.kind == tyError:
|
||||||
|
# a type error doesn't have any builtin fields
|
||||||
|
return nil
|
||||||
|
|
||||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||||
ty = ty.lastSon
|
ty = ty.lastSon
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
|
||||||
n = reResolveCallsWithTypedescParams(cl, n)
|
n = reResolveCallsWithTypedescParams(cl, n)
|
||||||
result = if cl.allowMetaTypes: n
|
result = if cl.allowMetaTypes: n
|
||||||
else: cl.c.semExpr(cl.c, n)
|
else: cl.c.semExpr(cl.c, n)
|
||||||
|
if not cl.allowMetaTypes:
|
||||||
|
assert result.kind notin nkCallKinds
|
||||||
else:
|
else:
|
||||||
if n.len > 0:
|
if n.len > 0:
|
||||||
newSons(result, n.len)
|
newSons(result, n.len)
|
||||||
|
|
|
||||||
|
|
@ -2184,7 +2184,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
|
||||||
proc evalConstExprAux(module: PSym; idgen: IdGenerator;
|
proc evalConstExprAux(module: PSym; idgen: IdGenerator;
|
||||||
g: ModuleGraph; prc: PSym, n: PNode,
|
g: ModuleGraph; prc: PSym, n: PNode,
|
||||||
mode: TEvalMode): PNode =
|
mode: TEvalMode): PNode =
|
||||||
if g.config.errorCounter > 0: return n
|
#if g.config.errorCounter > 0: return n
|
||||||
let n = transformExpr(g, idgen, module, n)
|
let n = transformExpr(g, idgen, module, n)
|
||||||
setupGlobalCtx(module, g, idgen)
|
setupGlobalCtx(module, g, idgen)
|
||||||
var c = PCtx g.vm
|
var c = PCtx g.vm
|
||||||
|
|
@ -2262,7 +2262,7 @@ proc errorNode(idgen: IdGenerator; owner: PSym, n: PNode): PNode =
|
||||||
|
|
||||||
proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int;
|
proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstCounter: ref int;
|
||||||
n, nOrig: PNode, sym: PSym): PNode =
|
n, nOrig: PNode, sym: PSym): PNode =
|
||||||
if g.config.errorCounter > 0: return errorNode(idgen, module, n)
|
#if g.config.errorCounter > 0: return errorNode(idgen, module, n)
|
||||||
|
|
||||||
# XXX globalError() is ugly here, but I don't know a better solution for now
|
# XXX globalError() is ugly here, but I don't know a better solution for now
|
||||||
inc(g.config.evalMacroCounter)
|
inc(g.config.evalMacroCounter)
|
||||||
|
|
|
||||||
|
|
@ -505,6 +505,9 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let it = n[i]
|
let it = n[i]
|
||||||
if it.len == 1:
|
if it.len == 1:
|
||||||
# else stmt:
|
# else stmt:
|
||||||
|
if it[0].kind != nkNilLit or it[0].typ != nil:
|
||||||
|
# an nkNilLit with nil for typ implies there is no else branch, this
|
||||||
|
# avoids unused related errors as we've already consumed the dest
|
||||||
c.gen(it[0], dest)
|
c.gen(it[0], dest)
|
||||||
else:
|
else:
|
||||||
let b = rawGenLiteral(c, it)
|
let b = rawGenLiteral(c, it)
|
||||||
|
|
|
||||||
|
|
@ -41,15 +41,11 @@ echo r.age_human_yrs()
|
||||||
echo r
|
echo r
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
disabled:true
|
$nimsuggest --tester --maxresults:5 $file
|
||||||
$nimsuggest --tester $file
|
|
||||||
>sug $1
|
>sug $1
|
||||||
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None
|
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None
|
||||||
sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None
|
sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None
|
||||||
sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None
|
sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None
|
||||||
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None
|
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None
|
||||||
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None
|
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None
|
||||||
sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: <unknown>.};;$file;;4;;6;;"";;50;;None*
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: disabled due to semantic error reporting in nimsuggest results
|
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,3 @@ $nimsuggest --tester $file
|
||||||
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix
|
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix
|
||||||
sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix
|
sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#[
|
|
||||||
TODO: additional calls to `>sug $1` produces different output with errors,
|
|
||||||
possibly related to cached results from the first analysis, which refers
|
|
||||||
to expanded macros/templates which rely on imported symbols from `system`
|
|
||||||
module that are not present in this module.
|
|
||||||
]#
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@ discard """
|
||||||
cmd: "nim check $file"
|
cmd: "nim check $file"
|
||||||
errormsg: ""
|
errormsg: ""
|
||||||
nimout: '''
|
nimout: '''
|
||||||
t10734.nim(18, 1) Error: invalid indentation
|
t10734.nim(19, 1) Error: invalid indentation
|
||||||
t10734.nim(18, 6) Error: invalid indentation
|
t10734.nim(19, 6) Error: invalid indentation
|
||||||
t10734.nim(19, 7) Error: expression expected, but found '[EOF]'
|
t10734.nim(20, 7) Error: expression expected, but found '[EOF]'
|
||||||
t10734.nim(17, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()'
|
t10734.nim(18, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()'
|
||||||
t10734.nim(18, 6) Error: undeclared identifier: 'p'
|
t10734.nim(19, 6) Error: undeclared identifier: 'p'
|
||||||
t10734.nim(18, 6) Error: 'p' cannot be assigned to
|
t10734.nim(19, 6) Error: expression 'p' has no type (or is ambiguous)
|
||||||
t10734.nim(16, 3) Hint: 'T' is declared but not used [XDeclaredButNotUsed]
|
t10734.nim(19, 6) Error: 'p' cannot be assigned to
|
||||||
|
t10734.nim(17, 3) Hint: 'T' is declared but not used [XDeclaredButNotUsed]
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,20 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
test1
|
||||||
|
test2
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
import jsffi
|
import jsffi
|
||||||
|
|
||||||
|
type
|
||||||
|
C = object
|
||||||
|
props: int
|
||||||
|
|
||||||
|
var c: C
|
||||||
|
|
||||||
when compiles(c.props):
|
when compiles(c.props):
|
||||||
echo "test"
|
echo "test1"
|
||||||
|
|
||||||
|
when not compiles(d.props):
|
||||||
|
echo "test2"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue