borrow checking (#15282)

* refactoring: move procs to typeallowed.nim
* frontend preparations for first class openArray support
* prepare the code generator for first class openArray
* code generation for first class openArray; WIP
* code generation for open arrays, progress
* added isViewType proc
* preparations for borrow checking
* added borrow checking to the front end
This commit is contained in:
Andreas Rumpf 2020-09-09 07:32:03 +02:00 • committed by GitHub
commit 10988d4840
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 554 additions and 311 deletions

View file

@ -329,7 +329,7 @@ proc containsTyRef*(typ: PType): bool =
result = searchTypeFor(typ, isTyRef)
proc isHiddenPointer(t: PType): bool =
result = t.kind in {tyString, tySequence}
result = t.kind in {tyString, tySequence, tyOpenArray, tyVarargs}
proc containsHiddenPointer*(typ: PType): bool =
# returns true if typ contains a string, table or sequence (all the things
@ -1240,37 +1240,6 @@ proc commonSuperclass*(a, b: PType): PType =
return t
y = y[0]
type
TTypeAllowedFlag* = enum
taField,
taHeap,
taConcept,
taIsOpenArray,
taNoUntyped
taIsTemplateOrMacro
taProcContextIsNotMacro
TTypeAllowedFlags* = set[TTypeAllowedFlag]
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType =
if n != nil:
result = typeAllowedAux(marker, n.typ, kind, flags)
if result == nil:
case n.kind
of nkNone..nkNilLit:
discard
else:
#if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
# return n[0].typ
for i in 0..<n.len:
let it = n[i]
result = typeAllowedNode(marker, it, kind, flags)
if result != nil: break
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
last: TTypeKind): bool =
var a = a
@ -1280,143 +1249,6 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
a = a[i]
result = a.kind == last
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType =
assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
# if we have already checked the type, return true, because we stop the
# evaluation if something is wrong:
result = nil
if typ == nil: return nil
if containsOrIncl(marker, typ.id): return nil
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
case t.kind
of tyVar, tyLent:
if kind in {skProc, skFunc, skConst}:
result = t
elif t.kind == tyLent and kind != skResult:
result = t
else:
var t2 = skipTypes(t[0], abstractInst-{tyTypeDesc})
case t2.kind
of tyVar, tyLent:
if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
of tyOpenArray:
if kind != skParam or taIsOpenArray in flags: result = t
else: result = typeAllowedAux(marker, t2[0], kind, flags+{taIsOpenArray})
of tyUncheckedArray:
if kind != skParam: result = t
else: result = typeAllowedAux(marker, t2[0], kind, flags)
else:
if kind notin {skParam, skResult}: result = t
else: result = typeAllowedAux(marker, t2, kind, flags)
of tyProc:
if kind in {skVar, skLet, skConst} and taIsTemplateOrMacro in flags:
result = t
else:
if isInlineIterator(typ) and kind in {skVar, skLet, skConst, skParam, skResult}:
# only closure iterators may be assigned to anything.
result = t
let f = if kind in {skProc, skFunc}: flags+{taNoUntyped} else: flags
for i in 1..<t.len:
if result != nil: break
result = typeAllowedAux(marker, t[i], skParam, f-{taIsOpenArray})
if result.isNil and t[0] != nil:
result = typeAllowedAux(marker, t[0], skResult, flags)
of tyTypeDesc:
if kind in {skVar, skLet, skConst} and taProcContextIsNotMacro in flags:
result = t
else:
# XXX: This is still a horrible idea...
result = nil
of tyUntyped, tyTyped:
if kind notin {skParam, skResult} or taNoUntyped in flags: result = t
of tyStatic:
if kind notin {skParam}: result = t
of tyVoid:
if taField notin flags: result = t
of tyTypeClasses:
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
discard
elif t.isResolvedUserTypeClass:
result = typeAllowedAux(marker, t.lastSon, kind, flags)
elif kind notin {skParam, skResult}:
result = t
of tyGenericBody, tyGenericParam, tyGenericInvocation,
tyNone, tyForward, tyFromExpr:
result = t
of tyNil:
if kind != skConst and kind != skParam: result = t
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
result = nil
of tyOrdinal:
if kind != skParam: result = t
of tyGenericInst, tyDistinct, tyAlias, tyInferred:
result = typeAllowedAux(marker, lastSon(t), kind, flags)
of tyRange:
if skipTypes(t[0], abstractInst-{tyTypeDesc}).kind notin
{tyChar, tyEnum, tyInt..tyFloat128, tyInt..tyUInt64}: result = t
of tyOpenArray, tyVarargs, tySink:
# you cannot nest openArrays/sinks/etc.
if kind != skParam or taIsOpenArray in flags:
result = t
else:
result = typeAllowedAux(marker, t[0], kind, flags+{taIsOpenArray})
of tyUncheckedArray:
if kind != skParam and taHeap notin flags:
result = t
else:
result = typeAllowedAux(marker, lastSon(t), kind, flags-{taHeap})
of tySequence:
if t[0].kind != tyEmpty:
result = typeAllowedAux(marker, t[0], kind, flags+{taHeap})
elif kind in {skVar, skLet}:
result = t[0]
of tyArray:
if t[1].kind == tyTypeDesc:
result = t[1]
elif t[1].kind != tyEmpty:
result = typeAllowedAux(marker, t[1], kind, flags)
elif kind in {skVar, skLet}:
result = t[1]
of tyRef:
if kind == skConst: result = t
else: result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
of tyPtr:
result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
of tySet:
for i in 0..<t.len:
result = typeAllowedAux(marker, t[i], kind, flags)
if result != nil: break
of tyObject, tyTuple:
if kind in {skProc, skFunc, skConst} and
t.kind == tyObject and t[0] != nil:
result = t
else:
let flags = flags+{taField}
for i in 0..<t.len:
result = typeAllowedAux(marker, t[i], kind, flags)
if result != nil: break
if result.isNil and t.n != nil:
result = typeAllowedNode(marker, t.n, kind, flags)
of tyEmpty:
if kind in {skVar, skLet}: result = t
of tyProxy:
# for now same as error node; we say it's a valid type as it should
# prevent cascading errors:
result = nil
of tyOwned:
if t.len == 1 and t[0].skipTypes(abstractInst).kind in {tyRef, tyPtr, tyProc}:
result = typeAllowedAux(marker, t.lastSon, kind, flags+{taHeap})
else:
result = t
of tyOptDeprecated: doAssert false
proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
# returns 'nil' on success and otherwise the part of the type that is
# wrong!
var marker = initIntSet()
result = typeAllowedAux(marker, t, kind, flags)
include sizealignoffsetimpl
proc computeSize*(conf: ConfigRef; typ: PType): BiggestInt =