decent borrow check for --newruntime
This commit is contained in:
parent
1ff2b021a5
commit
9ad96b58e6
2 changed files with 48 additions and 11 deletions
|
|
@ -1526,23 +1526,52 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||||
x.typ.flags.incl tfVarIsPtr
|
x.typ.flags.incl tfVarIsPtr
|
||||||
#echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
|
#echo x.info, " setting it for this type ", typeToString(x.typ), " ", n.info
|
||||||
|
|
||||||
proc asgnToResult(c: PContext, n, le, ri: PNode) =
|
proc borrowCheck(c: PContext, n, le, ri: PNode) =
|
||||||
|
const
|
||||||
|
PathKinds0 = {nkDotExpr, nkCheckedFieldExpr,
|
||||||
|
nkBracketExpr, nkAddr, nkHiddenAddr,
|
||||||
|
nkObjDownConv, nkObjUpConv}
|
||||||
|
PathKinds1 = {nkHiddenStdConv, nkHiddenSubConv}
|
||||||
|
|
||||||
|
proc getRoot(n: PNode; followDeref: bool): PNode =
|
||||||
|
result = n
|
||||||
|
while true:
|
||||||
|
case result.kind
|
||||||
|
of nkDerefExpr, nkHiddenDeref:
|
||||||
|
if followDeref: result = result[0]
|
||||||
|
else: break
|
||||||
|
of PathKinds0:
|
||||||
|
result = result[0]
|
||||||
|
of PathKinds1:
|
||||||
|
result = result[1]
|
||||||
|
else: break
|
||||||
|
|
||||||
proc scopedLifetime(c: PContext; ri: PNode): bool {.inline.} =
|
proc scopedLifetime(c: PContext; ri: PNode): bool {.inline.} =
|
||||||
|
let n = getRoot(ri, followDeref = false)
|
||||||
result = (ri.kind in nkCallKinds+{nkObjConstr}) or
|
result = (ri.kind in nkCallKinds+{nkObjConstr}) or
|
||||||
(ri.kind == nkSym and ri.sym.owner == c.p.owner)
|
(n.kind == nkSym and n.sym.owner == c.p.owner)
|
||||||
|
|
||||||
|
proc escapes(c: PContext; le: PNode): bool {.inline.} =
|
||||||
|
# param[].foo[] = self definitely escapes, we don't need to
|
||||||
|
# care about pointer derefs:
|
||||||
|
let n = getRoot(le, followDeref = true)
|
||||||
|
result = n.kind == nkSym and n.sym.kind == skParam
|
||||||
|
|
||||||
# Special typing rule: do not allow to pass 'owned T' to 'T' in 'result = x':
|
# Special typing rule: do not allow to pass 'owned T' to 'T' in 'result = x':
|
||||||
const absInst = abstractInst - {tyOwned}
|
const absInst = abstractInst - {tyOwned}
|
||||||
if ri.typ != nil and ri.typ.skipTypes(absInst).kind == tyOwned and
|
if ri.typ != nil and ri.typ.skipTypes(absInst).kind == tyOwned and
|
||||||
le.typ != nil and le.typ.skipTypes(absInst).kind != tyOwned and
|
le.typ != nil and le.typ.skipTypes(absInst).kind != tyOwned and
|
||||||
scopedLifetime(c, ri):
|
scopedLifetime(c, ri):
|
||||||
|
if le.kind == nkSym and le.sym.kind == skResult:
|
||||||
localError(c.config, n.info, "cannot return an owned pointer as an unowned pointer; " &
|
localError(c.config, n.info, "cannot return an owned pointer as an unowned pointer; " &
|
||||||
"use 'owned(" & typeToString(le.typ) & ")' as the return type")
|
"use 'owned(" & typeToString(le.typ) & ")' as the return type")
|
||||||
|
elif escapes(c, le):
|
||||||
|
localError(c.config, n.info,
|
||||||
|
"assignment produces a dangling ref: the unowned ref lives longer than the owned ref")
|
||||||
|
|
||||||
template resultTypeIsInferrable(typ: PType): untyped =
|
template resultTypeIsInferrable(typ: PType): untyped =
|
||||||
typ.isMetaType and typ.kind != tyTypeDesc
|
typ.isMetaType and typ.kind != tyTypeDesc
|
||||||
|
|
||||||
|
|
||||||
proc goodLineInfo(arg: PNode): TLineinfo =
|
proc goodLineInfo(arg: PNode): TLineinfo =
|
||||||
if arg.kind == nkStmtListExpr and arg.len > 0:
|
if arg.kind == nkStmtListExpr and arg.len > 0:
|
||||||
goodLineInfo(arg[^1])
|
goodLineInfo(arg[^1])
|
||||||
|
|
@ -1629,7 +1658,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
c.p.owner.typ.sons[0] = rhsTyp
|
c.p.owner.typ.sons[0] = rhsTyp
|
||||||
else:
|
else:
|
||||||
typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
|
typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
|
||||||
asgnToResult(c, n, n.sons[0], rhs)
|
borrowCheck(c, n, lhs, rhs)
|
||||||
|
|
||||||
n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
|
n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
|
||||||
liftTypeBoundOps(c, lhs.typ, lhs.info)
|
liftTypeBoundOps(c, lhs.typ, lhs.info)
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.})
|
||||||
|
|
||||||
expression: new(result)
|
expression: new(result)
|
||||||
tdont_return_unowned_from_owned.nim(30, 6) Error: illformed AST:
|
tdont_return_unowned_from_owned.nim(30, 6) Error: illformed AST:
|
||||||
|
tdont_return_unowned_from_owned.nim(38, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
|
||||||
|
tdont_return_unowned_from_owned.nim(39, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
|
||||||
|
tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type
|
||||||
'''
|
'''
|
||||||
errormsg: "illformed AST:"
|
errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type"
|
||||||
line: 30
|
line: 43
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# bug #11073
|
# bug #11073
|
||||||
type
|
type
|
||||||
Obj = ref object
|
Obj = ref object
|
||||||
|
|
@ -33,3 +33,11 @@ let a = newObjA()
|
||||||
let b = newObjB()
|
let b = newObjB()
|
||||||
let c = newObjC()
|
let c = newObjC()
|
||||||
|
|
||||||
|
proc testA(result: var (RootRef, RootRef)) =
|
||||||
|
let r: owned RootRef = RootRef()
|
||||||
|
result[0] = r
|
||||||
|
result[1] = RootRef()
|
||||||
|
|
||||||
|
proc testB(): RootRef =
|
||||||
|
let r: owned RootRef = RootRef()
|
||||||
|
result = r
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue