Skip to content

Commit

Permalink
fixes #20681; add efSkipFieldVisibilityCheck to skip check (#20639)
Browse files Browse the repository at this point in the history
* don't sem const objectConstr defaults

* fixes

* add `efSkipFieldVisibilityCheck`; fixes nkBracket types

* fixes #20681

* fixes tests

* suggestion from @metagn

* fixes tests

Co-authored-by: xflywind <[email protected]>
  • Loading branch information
ringabout and ringabout authored Oct 28, 2022
1 parent 779b1cc commit 141abb7
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 47 deletions.
3 changes: 2 additions & 1 deletion compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ type
efWantStmt, efAllowStmt, efDetermineType, efExplain,
efWantValue, efOperand, efNoSemCheck,
efNoEvaluateGeneric, efInCall, efFromHlo, efNoSem2Check,
efNoUndeclared, efIsDotCall, efCannotBeDotCall
efNoUndeclared, efIsDotCall, efCannotBeDotCall,
efSkipFieldVisibilityCheck
# Use this if undeclared identifiers should not raise an error during
# overload resolution.

Expand Down
3 changes: 2 additions & 1 deletion compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3075,7 +3075,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of paTupleFields: result = semTupleFieldsConstr(c, n, flags, expectedType)
of paSingle: result = semExpr(c, n[0], flags, expectedType)
of nkCurly: result = semSetConstr(c, n, expectedType)
of nkBracket: result = semArrayConstr(c, n, flags, expectedType)
of nkBracket:
result = semArrayConstr(c, n, flags, expectedType)
of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
of nkDerefExpr: result = semDeref(c, n)
Expand Down
8 changes: 6 additions & 2 deletions compiler/semobjconstr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ proc semConstrField(c: PContext, flags: TExprFlags,
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
if nfUseDefaultField in assignment[1].flags:
if nfUseDefaultField in assignment[1].flags or
efSkipFieldVisibilityCheck in flags:
discard
elif not fieldVisible(c, field):
localError(c.config, initExpr.info,
Expand Down Expand Up @@ -415,7 +416,10 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
# field (if this is a case object, initialized fields in two different
# branches will be reported as an error):
var constrCtx = initConstrContext(t, result)
let (initResult, defaults) = semConstructTypeAux(c, constrCtx, flags)
let (initResult, defaults) = if nfUseDefaultField in n.flags:
semConstructTypeAux(c, constrCtx, flags + {efSkipFieldVisibilityCheck})
else:
semConstructTypeAux(c, constrCtx, flags)
result[0].sons.add defaults
var hasError = false # needed to split error detect/report for better msgs

Expand Down
26 changes: 12 additions & 14 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
else:
return false

proc fitDefaultNode(c: PContext, n: PNode): PType =
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
if n[^2].kind != nkEmpty:
if expectedType != nil:
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
result = n[^1].typ
else:
result = n[^1].typ

proc isRecursiveType*(t: PType): bool =
# handle simple recusive types before typeFinalPass
var cycleDetector = initIntSet()
Expand Down Expand Up @@ -484,13 +494,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(a, 3, c.config)
var hasDefaultField = a[^1].kind != nkEmpty
if hasDefaultField:
a[^1] = semConstExpr(c, a[^1])
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
let def = semExprWithType(c, a[^1], {}, typ)
typ = fitNodeConsiderViewType(c, typ, def, def.info).typ
else:
typ = a[^1].typ
typ = fitDefaultNode(c, a)
elif a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
Expand Down Expand Up @@ -824,13 +828,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
var typ: PType
var hasDefaultField = n[^1].kind != nkEmpty
if hasDefaultField:
n[^1] = semConstExpr(c, n[^1])
if n[^2].kind != nkEmpty:
typ = semTypeNode(c, n[^2], nil)
let def = semExprWithType(c, n[^1], {}, typ)
typ = fitNodeConsiderViewType(c, typ, def, def.info).typ
else:
typ = n[^1].typ
typ = fitDefaultNode(c, n)
propagateToOwner(rectype, typ)
elif n[^2].kind == nkEmpty:
localError(c.config, n.info, errTypeExpected)
Expand Down
9 changes: 3 additions & 6 deletions tests/objects/tdefaultfieldscheck.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ discard """
errormsg: ""
nimout:
'''
tdefaultfieldscheck.nim(17, 17) Error: type mismatch: got <string> but expected 'int'
tdefaultfieldscheck.nim(18, 20) Error: type mismatch: got <int literal(12)> but expected 'string'
tdefaultfieldscheck.nim(20, 16) Error: type mismatch: got <float64> but expected 'int'
tdefaultfieldscheck.nim(17, 5) Error: type mismatch: got <string> but expected 'int'
tdefaultfieldscheck.nim(18, 5) Error: type mismatch: got <int literal(12)> but expected 'string'
tdefaultfieldscheck.nim(20, 5) Error: type mismatch: got <float64> but expected 'int'
tdefaultfieldscheck.nim(14, 17) Error: type mismatch: got <string> but expected 'int'
tdefaultfieldscheck.nim(15, 20) Error: type mismatch: got <int literal(12)> but expected 'string'
tdefaultfieldscheck.nim(17, 16) Error: type mismatch: got <float64> but expected 'int'
'''
"""

Expand Down
2 changes: 1 addition & 1 deletion tests/objects/tdefaultrangetypescheck.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
discard """
errormsg: "conversion from int literal(0) to range 1..5(int) is invalid"
errormsg: "cannot convert 0 to range 1..5(int)"
line: 9
"""

Expand Down
46 changes: 24 additions & 22 deletions tests/objects/tobject_default_value.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ discard """
targets: "c cpp js"
"""

import times
import std/[times, tables]

type
Guess = object
Expand Down Expand Up @@ -222,6 +222,18 @@ template main {.dirty.} =
doAssert y.time == 1.2
doAssert y.scale == 1

block:
var my = @[1, 2, 3, 4, 5]
my.setLen(0)
my.setLen(5)
doAssert my == @[0, 0, 0, 0, 0]

block:
var my = "hello"
my.setLen(0)
my.setLen(5)
doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']"""

block: # array
var x: array[10, Object] = arrayWith(default(Object), 10)
let y = x[0]
Expand Down Expand Up @@ -379,20 +391,19 @@ template main {.dirty.} =
doAssert x.id == 1
doAssert x.obj == default(ObjectBase)
doAssert x.name == ""

block:
var x = default(Class)
doAssert x.def == default(Default)
doAssert x.def.id == 1
doAssert x.def.obj == default(ObjectBase)
doAssert x.def.name == ""

when not defined(cpp):
block:
var x = default(Member)
doAssert x.def.id == 777
doAssert x.def.obj == default(ObjectBase)
doAssert x.def.name == "fine"
block:
var x = default(Member)
doAssert x.def.id == 777
doAssert x.def.obj == default(ObjectBase)
doAssert x.def.name == "fine"

block:
var x {.noinit.} = 12
Expand All @@ -408,22 +419,13 @@ template main {.dirty.} =
var z {.noinit.}: Pure = Pure(id: 77)
doAssert z.id == 77

block: # bug #20681
type A = object
d: DateTime = DateTime()

proc main1 =
var my = @[1, 2, 3, 4, 5]
my.setLen(0)
my.setLen(5)
doAssert my == @[0, 0, 0, 0, 0]

proc main2 =
var my = "hello"
my.setLen(0)
my.setLen(5)
doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']"""
let x = default(A)
doAssert $x == "(d: Uninitialized DateTime)"

when defined(gcArc) or defined(gcOrc):
main1()
main2()

static: main()
main()

0 comments on commit 141abb7

Please sign in to comment.