Skip to content

Commit

Permalink
Nonref object inheritance now hints and converts to base in varargs a…
Browse files Browse the repository at this point in the history
…nd on assignment
  • Loading branch information
beef331 committed Nov 23, 2021
1 parent ff761eb commit 3457eab
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 82 deletions.
11 changes: 7 additions & 4 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,9 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# tfShallow flag for the built-in string type too! So we check only
# here for this flag, where it is reasonably safe to do so
# (for objects, etc.):
if optSeqDestructors in p.config.globalOptions:
if optSeqDestructors in p.config.globalOptions or src.lode.kind in {nkObjUpConv, nkObjDownConv}:
# If it's an up/down conv it's an non-ref -> non-ref inheritance which is a copy or assignment.
# As such the assignment is direct, semantic analysis should handle any errors statically.
linefmt(p, cpsStmts,
"$1 = $2;$n",
[rdLoc(dest), rdLoc(src)])
Expand Down Expand Up @@ -2604,11 +2606,12 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
else:
genTypeInfoV1(p.module, dest, n.info)
if nilCheck != nil:
# We only need to do a conversion check if it's a ref object.
# Since with non refs either a copy is done or a ptr to the element is passed,
# there is nothing dynamic with them and the compiler knows the error happens at semantic analysis.
linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n",
[nilCheck, r, checkFor, raiseInstr(p)])
else:
linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); $3}$n",
[r, checkFor, raiseInstr(p)])

if n[0].typ.kind != tyObject:
if n.isLValue:
putIntoDest(p, d, n,
Expand Down
2 changes: 2 additions & 0 deletions compiler/lineinfos.nim
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
hintImplicitObjConv = "ImplicitObjConv"

const
MsgKindToStr*: array[TMsgKind, string] = [
Expand Down Expand Up @@ -202,6 +203,7 @@ const
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1",
hintImplicitObjConv: "'$1' implicitly converted to '$2' [$3]"
]

const
Expand Down
5 changes: 5 additions & 0 deletions compiler/transf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -569,10 +569,15 @@ proc transformConv(c: PTransf, n: PNode): PNode =
result = transformSons(c, n)
of tyObject:
var diff = inheritanceDiff(dest, source)
template convHint =
if n.kind == nkHiddenSubConv:
rawMessage(c.graph.config, hintImplicitObjConv, [$n[1], typeToString(dest), toFileLineCol(c.graph.config, n[1].info)])
if diff < 0:
convHint()
result = newTransNode(nkObjUpConv, n, 1)
result[0] = transform(c, n[1])
elif diff > 0 and diff != high(int):
convHint()
result = newTransNode(nkObjDownConv, n, 1)
result[0] = transform(c, n[1])
else:
Expand Down
12 changes: 0 additions & 12 deletions tests/objects/t4318.nim

This file was deleted.

24 changes: 0 additions & 24 deletions tests/objects/tobj_asgn_dont_slice.nim

This file was deleted.

21 changes: 0 additions & 21 deletions tests/typerel/t4799_2.nim

This file was deleted.

21 changes: 0 additions & 21 deletions tests/typerel/t4799_3.nim

This file was deleted.

55 changes: 55 additions & 0 deletions tests/types/tnonref_inheritance_conversion.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
discard """
cmd: "nim c --hint[Conf]:off --verbosity:0 $file"
nimout: '''
Hint: 'Derived()' implicitly converted to 'Base' [tnonref_inheritance_conversion.nim(30, 13)] [ImplicitObjConv]
Hint: 'Derived()' implicitly converted to 'Base' [tnonref_inheritance_conversion.nim(30, 32)] [ImplicitObjConv]
Hint: 'a' implicitly converted to 'Base' [tnonref_inheritance_conversion.nim(32, 7)] [ImplicitObjConv]
Hint: 'b' implicitly converted to 'Base' [tnonref_inheritance_conversion.nim(36, 1)] [ImplicitObjConv]
'''
"""


type
Base {.inheritable.} = object
field: int

Derived = object of Base
field2: int
field3: int
Derived2 = object of Base

proc test(args: varargs[Base]) =
for x in args:
assert x.field == 0

proc test2(base: var Base) = base.field = 400

var a: Derived = Derived(Base())
a = Derived(Base(Derived2()))
test(Derived(), Base(), Derived())
a.field2 = 300
test2(a)
assert a.field == 400
assert a.field2 == 300
var b = Derived2(field: 800)
b.test2()
assert b.field == 400



block:
type
Base = ref object of RootObj
field: int
Derived = ref object of Base
field2: int
Derived2 = ref object of Base

var a: Base = Derived()
assert Derived(a) is Derived
doAssertRaises(ObjectConversionDefect): discard Derived2(a)[]
doAssertRaises(ObjectConversionDefect): discard Base(Derived2()).Derived
assert Base(Derived()) is Base
assert Derived2(Base(Derived2())) is Derived2
assert Derived(Base(Derived())) is Derived

0 comments on commit 3457eab

Please sign in to comment.