From 141abb7b75e1dcea8c138ba625831cce7e314e4a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 29 Oct 2022 04:19:40 +0800 Subject: [PATCH] fixes #20681; add efSkipFieldVisibilityCheck to skip check (#20639) * 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 <43030857+xflywind@users.noreply.github.com> --- compiler/semdata.nim | 3 +- compiler/semexprs.nim | 3 +- compiler/semobjconstr.nim | 8 +++- compiler/semtypes.nim | 26 ++++++------- tests/objects/tdefaultfieldscheck.nim | 9 ++--- tests/objects/tdefaultrangetypescheck.nim | 2 +- tests/objects/tobject_default_value.nim | 46 ++++++++++++----------- 7 files changed, 50 insertions(+), 47 deletions(-) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 337b5f867e1b9..d1ffab5ebc886 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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. diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 08fc4f98f14f0..39649fa271222 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 1463ba8332434..e516849139596 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -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, @@ -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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5dfcbac52c3c1..5461b7983a9d9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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() @@ -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: @@ -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) diff --git a/tests/objects/tdefaultfieldscheck.nim b/tests/objects/tdefaultfieldscheck.nim index 9c648ed2b7c16..d6feb29883c2e 100644 --- a/tests/objects/tdefaultfieldscheck.nim +++ b/tests/objects/tdefaultfieldscheck.nim @@ -3,12 +3,9 @@ discard """ errormsg: "" nimout: ''' -tdefaultfieldscheck.nim(17, 17) Error: type mismatch: got but expected 'int' -tdefaultfieldscheck.nim(18, 20) Error: type mismatch: got but expected 'string' -tdefaultfieldscheck.nim(20, 16) Error: type mismatch: got but expected 'int' -tdefaultfieldscheck.nim(17, 5) Error: type mismatch: got but expected 'int' -tdefaultfieldscheck.nim(18, 5) Error: type mismatch: got but expected 'string' -tdefaultfieldscheck.nim(20, 5) Error: type mismatch: got but expected 'int' +tdefaultfieldscheck.nim(14, 17) Error: type mismatch: got but expected 'int' +tdefaultfieldscheck.nim(15, 20) Error: type mismatch: got but expected 'string' +tdefaultfieldscheck.nim(17, 16) Error: type mismatch: got but expected 'int' ''' """ diff --git a/tests/objects/tdefaultrangetypescheck.nim b/tests/objects/tdefaultrangetypescheck.nim index 50eeac492efa9..71e7ac59ba2d4 100644 --- a/tests/objects/tdefaultrangetypescheck.nim +++ b/tests/objects/tdefaultrangetypescheck.nim @@ -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 """ diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index efbce3658ae16..643bba832cb1d 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -3,7 +3,7 @@ discard """ targets: "c cpp js" """ -import times +import std/[times, tables] type Guess = object @@ -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] @@ -379,7 +391,7 @@ 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) @@ -387,12 +399,11 @@ template main {.dirty.} = 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 @@ -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()