const view types; fixes some cases from https://github.com/nim-lang/Nim/issues/15428 (#15488)

This commit is contained in:
Andreas Rumpf 2020-10-05 18:31:46 +02:00 • committed by GitHub
commit 4e438f9096
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 47 deletions

View file

@ -591,10 +591,17 @@ proc value(this: var DebugPrinter; value: PNode) =
if this.conf != nil: if this.conf != nil:
this.key "info" this.key "info"
this.value $lineInfoToStr(this.conf, value.info) this.value $lineInfoToStr(this.conf, value.info)
if card(value.flags) > 0: if value.flags != {}:
this.key "flags" this.key "flags"
this.value value.flags this.value value.flags
if value.typ != nil:
this.key "typ"
this.value value.typ.kind
else:
this.key "typ"
this.value "nil"
case value.kind case value.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
this.key "intVal" this.key "intVal"

View file

@ -1400,7 +1400,7 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
# expression not found in the cache: # expression not found in the cache:
inc(p.module.labels) inc(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)]) [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true, t)])
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr: if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
@ -2485,7 +2485,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
inc(p.module.labels) inc(p.module.labels)
var tmp = "CNSTCLOSURE" & rope(p.module.labels) var tmp = "CNSTCLOSURE" & rope(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true)]) [getTypeDesc(p.module, n.typ), tmp, genBracedInit(p, n, isConst = true, n.typ)])
putIntoDest(p, d, n, tmp, OnStatic) putIntoDest(p, d, n, tmp, OnStatic)
else: else:
var tmp, a, b: TLoc var tmp, a, b: TLoc
@ -2624,7 +2624,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
# expression not found in the cache: # expression not found in the cache:
inc(p.module.labels) inc(p.module.labels)
p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n", p.module.s[cfsData].addf("static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genBracedInit(p, n, isConst = true)]) [getTypeDesc(p.module, t, skConst), tmp, genBracedInit(p, n, isConst = true, t)])
if d.k == locNone: if d.k == locNone:
fillLoc(d, locData, n, tmp, OnStatic) fillLoc(d, locData, n, tmp, OnStatic)
@ -2847,8 +2847,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind") else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope = proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst) if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst, n[0].typ)
else: result = genBracedInit(p, n, isConst) else: result = genBracedInit(p, n, isConst, n.typ)
proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope = proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc}) var t = skipTypes(typ, abstractRange+{tyOwned}-{tyTypeDesc})
@ -2955,10 +2955,10 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
for i in 1..<constOrNil.len: for i in 1..<constOrNil.len:
if constOrNil[i].kind == nkExprColonExpr: if constOrNil[i].kind == nkExprColonExpr:
if constOrNil[i][0].sym.name.id == field.name.id: if constOrNil[i][0].sym.name.id == field.name.id:
result.add genBracedInit(p, constOrNil[i][1], isConst) result.add genBracedInit(p, constOrNil[i][1], isConst, field.typ)
return return
elif i == field.position: elif i == field.position:
result.add genBracedInit(p, constOrNil[i], isConst) result.add genBracedInit(p, constOrNil[i], isConst, field.typ)
return return
# not found, produce default value: # not found, produce default value:
result.add getDefaultValue(p, field.typ, info) result.add getDefaultValue(p, field.typ, info)
@ -2999,25 +2999,35 @@ proc genConstObjConstr(p: BProc; n: PNode; isConst: bool): Rope =
proc genConstSimpleList(p: BProc, n: PNode; isConst: bool): Rope = proc genConstSimpleList(p: BProc, n: PNode; isConst: bool): Rope =
result = rope("{") result = rope("{")
for i in 0..<n.len - 1: for i in 0..<n.len:
result.addf("$1,$n", [genNamedConstExpr(p, n[i], isConst)]) let it = n[i]
if n.len > 0: if i > 0: result.add ",\n"
result.add(genNamedConstExpr(p, n[^1], isConst)) if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, it[0].typ)
result.addf("}$n", []) else: result.add genBracedInit(p, it, isConst, it.typ)
result.add("}\n")
proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType): Rope =
result = rope("{")
for i in 0..<n.len:
let it = n[i]
if i > 0: result.add ",\n"
if it.kind == nkExprColonExpr: result.add genBracedInit(p, it[1], isConst, tup[i])
else: result.add genBracedInit(p, it, isConst, tup[i])
result.add("}\n")
proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope = proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope] var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope]
let base = t.skipTypes(abstractInst)[0]
if n.len > 0: if n.len > 0:
# array part needs extra curlies: # array part needs extra curlies:
data.add(", {") data.add(", {")
for i in 0..<n.len: for i in 0..<n.len:
if i > 0: data.addf(",$n", []) if i > 0: data.addf(",$n", [])
data.add genBracedInit(p, n[i], isConst) data.add genBracedInit(p, n[i], isConst, base)
data.add("}") data.add("}")
data.add("}") data.add("}")
result = getTempName(p.module) result = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData, appcg(p.module, cfsData,
"static $5 struct {$n" & "static $5 struct {$n" &
@ -3030,14 +3040,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
result = "(($1)&$2)" % [getTypeDesc(p.module, t), result] result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope = proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
let base = t.skipTypes(abstractInst)[0]
var data = rope"{" var data = rope"{"
for i in 0..<n.len: for i in 0..<n.len:
if i > 0: data.addf(",$n", []) if i > 0: data.addf(",$n", [])
data.add genBracedInit(p, n[i], isConst) data.add genBracedInit(p, n[i], isConst, base)
data.add("}") data.add("}")
let payload = getTempName(p.module) let payload = getTempName(p.module)
let base = t.skipTypes(abstractInst)[0]
appcg(p.module, cfsData, appcg(p.module, cfsData,
"static $5 struct {$n" & "static $5 struct {$n" &
@ -3047,46 +3057,32 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
if isConst: "const" else: ""]) if isConst: "const" else: ""])
result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope = proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope =
case n.kind case n.kind
of nkHiddenStdConv, nkHiddenSubConv: of nkHiddenStdConv, nkHiddenSubConv:
when false: result = genBracedInit(p, n[1], isConst, n.typ)
# XXX The frontend doesn't keep conversions to openArray for us. :-(
# We need to change 'transformConv' first, but that is hard.
if n.typ.kind == tyOpenArray:
assert n[1].kind == nkBracket
let data = genBracedInit(p, n[1], isConst)
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, n.typ.skipTypes(abstractInst)[0])
let arrLen = n[1].len
appcg(p.module, cfsData,
"static $5 $1 $3[$2] = $4;$n", [
ctype, arrLen, payload, data,
if isConst: "const" else: ""])
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
else:
result = genBracedInit(p, n[1], isConst)
else: else:
var ty = tyNone var ty = tyNone
if n.typ == nil: var typ: PType = nil
if optionalType == nil:
if n.kind in nkStrKinds: if n.kind in nkStrKinds:
ty = tyString ty = tyString
else: else:
internalError(p.config, n.info, "node has no type") internalError(p.config, n.info, "node has no type")
else: else:
ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind typ = skipTypes(optionalType, abstractInstOwned + {tyStatic})
ty = typ.kind
case ty case ty
of tySet: of tySet:
let cs = toBitSet(p.config, n) let cs = toBitSet(p.config, n)
result = genRawSetData(cs, int(getSize(p.config, n.typ))) result = genRawSetData(cs, int(getSize(p.config, n.typ)))
of tySequence: of tySequence:
if optSeqDestructors in p.config.globalOptions: if optSeqDestructors in p.config.globalOptions:
result = genConstSeqV2(p, n, n.typ, isConst) result = genConstSeqV2(p, n, typ, isConst)
else: else:
result = genConstSeq(p, n, n.typ, isConst) result = genConstSeq(p, n, typ, isConst)
of tyProc: of tyProc:
if n.typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit: if typ.callConv == ccClosure and n.len > 1 and n[1].kind == nkNilLit:
# Conversion: nimcall -> closure. # Conversion: nimcall -> closure.
# this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
# this behaviour is needed since closure_var = nil must be # this behaviour is needed since closure_var = nil must be
@ -3099,13 +3095,30 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
else: else:
var d: TLoc var d: TLoc
initLocExpr(p, n[0], d) initLocExpr(p, n[0], d)
result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, n.typ, clHalfWithEnv), rdLoc(d)] result = "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)]
else: else:
var d: TLoc var d: TLoc
initLocExpr(p, n, d) initLocExpr(p, n, d)
result = rdLoc(d) result = rdLoc(d)
of tyArray, tyTuple, tyOpenArray, tyVarargs: of tyArray, tyVarargs:
result = genConstSimpleList(p, n, isConst) result = genConstSimpleList(p, n, isConst)
of tyTuple:
result = genConstTuple(p, n, isConst, typ)
of tyOpenArray:
if n.kind != nkBracket:
internalError(p.config, n.info, "const openArray expression is not an array construction")
let data = genConstSimpleList(p, n, isConst)
let payload = getTempName(p.module)
let ctype = getTypeDesc(p.module, typ[0])
let arrLen = n.len
appcg(p.module, cfsData,
"static $5 $1 $3[$2] = $4;$n", [
ctype, arrLen, payload, data,
if isConst: "const" else: ""])
result = "{($1*)&$2, $3}" % [ctype, payload, rope arrLen]
of tyObject: of tyObject:
result = genConstObjConstr(p, n, isConst) result = genConstObjConstr(p, n, isConst)
of tyString, tyCString: of tyString, tyCString:

View file

@ -272,7 +272,7 @@ proc genGotoVar(p: BProc; value: PNode) =
else: else:
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope]) lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType): Rope
proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope = proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope =
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn: if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
@ -280,7 +280,7 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode): Rope =
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ): p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ):
#echo "New code produced for ", v.name.s, " ", p.config $ value.info #echo "New code produced for ", v.name.s, " ", p.config $ value.info
result = genBracedInit(p, value, isConst = false) result = genBracedInit(p, value, isConst = false, v.typ)
else: else:
result = nil result = nil

View file

@ -1195,7 +1195,8 @@ proc requestConstImpl(p: BProc, sym: PSym) =
# add a suffix for hcr - will later init the global pointer with this data # add a suffix for hcr - will later init the global pointer with this data
let actualConstName = if m.hcrOn: sym.loc.r & "_const" else: sym.loc.r let actualConstName = if m.hcrOn: sym.loc.r & "_const" else: sym.loc.r
q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n", q.s[cfsData].addf("N_LIB_PRIVATE NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), actualConstName, genBracedInit(q.initProc, sym.ast, isConst = true)]) [getTypeDesc(q, sym.typ), actualConstName,
genBracedInit(q.initProc, sym.ast, isConst = true, sym.typ)])
if m.hcrOn: if m.hcrOn:
# generate the global pointer with the real name # generate the global pointer with the real name
q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]) q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r])

View file

@ -217,7 +217,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind =
case t.kind case t.kind
of tyVar: of tyVar:
result = mutableView result = mutableView
of tyLent, tyVarargs, tyOpenArray: of tyLent, tyOpenArray:
result = immutableView result = immutableView
of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned, of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic: tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic:

View file

@ -1807,7 +1807,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
result.add getNullValue(t[i], info, conf) result.add getNullValue(t[i], info, conf)
of tySet: of tySet:
result = newNodeIT(nkCurly, info, t) result = newNodeIT(nkCurly, info, t)
of tySequence: of tySequence, tyOpenArray:
result = newNodeIT(nkBracket, info, t) result = newNodeIT(nkBracket, info, t)
else: else:
globalError(conf, info, "cannot create null element for: " & $t.kind) globalError(conf, info, "cannot create null element for: " & $t.kind)

View file

@ -0,0 +1,26 @@
discard """
cmd: "nim c --experimental:views $file"
output: '''(data: [1, 2, 3], other: 4)
[1, 20, 3]'''
"""
type
Foo = object
data: openArray[int]
other: int
const
c = Foo(data: [1, 2, 3], other: 4)
c2 = Foo(data: [1, 20, 3], other: 4)
proc `$`(x: openArray[int]): string =
result = "["
for i in x:
if result.len > 1: result.add ", "
result.add $i
result.add "]"
echo c
echo c2.data