summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2020-10-05 18:31:46 +0200
committerGitHub <noreply@github.com>2020-10-05 18:31:46 +0200
commit4e438f9096fc413824bdbe8377a4ca376d63be35 (patch)
tree3f3dd5907e3b8469423da747418e3d7abbdd4d81
parent1e28cea0d102afd43a62f6f7fcabd65cd8996762 (diff)
downloadNim-4e438f9096fc413824bdbe8377a4ca376d63be35.tar.gz
const view types; fixes some cases from https://github.com/nim-lang/Nim/issues/15428 (#15488)
-rw-r--r--compiler/astalgo.nim9
-rw-r--r--compiler/ccgexprs.nim95
-rw-r--r--compiler/ccgstmts.nim4
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/typeallowed.nim2
-rw-r--r--compiler/vmgen.nim2
-rw-r--r--tests/views/tconst_views.nim26
7 files changed, 94 insertions, 47 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 5e23d2284..6aecb1dcb 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -591,10 +591,17 @@ proc value(this: var DebugPrinter; value: PNode) =
   if this.conf != nil:
     this.key "info"
     this.value $lineInfoToStr(this.conf, value.info)
-  if card(value.flags) > 0:
+  if value.flags != {}:
     this.key "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
   of nkCharLit..nkUInt64Lit:
     this.key "intVal"
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index b58519614..364bcc143 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1400,7 +1400,7 @@ proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
     # expression not found in the cache:
     inc(p.module.labels)
     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 =
   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)
     var tmp = "CNSTCLOSURE" & rope(p.module.labels)
     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)
   else:
     var tmp, a, b: TLoc
@@ -2624,7 +2624,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
     # expression not found in the cache:
     inc(p.module.labels)
     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:
     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")
 
 proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =
-  if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst)
-  else: result = genBracedInit(p, n, isConst)
+  if n.kind == nkExprColonExpr: result = genBracedInit(p, n[1], isConst, n[0].typ)
+  else: result = genBracedInit(p, n, isConst, n.typ)
 
 proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
   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:
         if constOrNil[i].kind == nkExprColonExpr:
           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
         elif i == field.position:
-          result.add genBracedInit(p, constOrNil[i], isConst)
+          result.add genBracedInit(p, constOrNil[i], isConst, field.typ)
           return
     # not found, produce default value:
     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 =
   result = rope("{")
-  for i in 0..<n.len - 1:
-    result.addf("$1,$n", [genNamedConstExpr(p, n[i], isConst)])
-  if n.len > 0:
-    result.add(genNamedConstExpr(p, n[^1], isConst))
-  result.addf("}$n", [])
+  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, it[0].typ)
+    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 =
   var data = "{{$1, $1 | NIM_STRLIT_FLAG}" % [n.len.rope]
+  let base = t.skipTypes(abstractInst)[0]
   if n.len > 0:
     # array part needs extra curlies:
     data.add(", {")
     for i in 0..<n.len:
       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("}")
 
   result = getTempName(p.module)
-  let base = t.skipTypes(abstractInst)[0]
 
   appcg(p.module, cfsData,
         "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]
 
 proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
+  let base = t.skipTypes(abstractInst)[0]
   var data = rope"{"
   for i in 0..<n.len:
     if i > 0: data.addf(",$n", [])
-    data.add genBracedInit(p, n[i], isConst)
+    data.add genBracedInit(p, n[i], isConst, base)
   data.add("}")
 
   let payload = getTempName(p.module)
-  let base = t.skipTypes(abstractInst)[0]
 
   appcg(p.module, cfsData,
     "static $5 struct {$n" &
@@ -3047,46 +3057,32 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
     if isConst: "const" else: ""])
   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
   of nkHiddenStdConv, nkHiddenSubConv:
-    when false:
-      # 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)
+    result = genBracedInit(p, n[1], isConst, n.typ)
   else:
     var ty = tyNone
-    if n.typ == nil:
+    var typ: PType = nil
+    if optionalType == nil:
       if n.kind in nkStrKinds:
         ty = tyString
       else:
         internalError(p.config, n.info, "node has no type")
     else:
-      ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind
+      typ = skipTypes(optionalType, abstractInstOwned + {tyStatic})
+      ty = typ.kind
     case ty
     of tySet:
       let cs = toBitSet(p.config, n)
       result = genRawSetData(cs, int(getSize(p.config, n.typ)))
     of tySequence:
       if optSeqDestructors in p.config.globalOptions:
-        result = genConstSeqV2(p, n, n.typ, isConst)
+        result = genConstSeqV2(p, n, typ, isConst)
       else:
-        result = genConstSeq(p, n, n.typ, isConst)
+        result = genConstSeq(p, n, typ, isConst)
     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.
         # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL}
         # this behaviour is needed since closure_var = nil must be
@@ -3099,13 +3095,30 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
         else:
           var d: TLoc
           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:
         var d: TLoc
         initLocExpr(p, n, d)
         result = rdLoc(d)
-    of tyArray, tyTuple, tyOpenArray, tyVarargs:
+    of tyArray, tyVarargs:
       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:
       result = genConstObjConstr(p, n, isConst)
     of tyString, tyCString:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 5bed7cf32..1282cf11f 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -272,7 +272,7 @@ proc genGotoVar(p: BProc; value: PNode) =
   else:
     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 =
   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
       p.withinLoop == 0 and not containsGarbageCollectedRef(v.typ):
     #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:
     result = nil
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index f50676647..9a50b718c 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1195,7 +1195,8 @@ proc requestConstImpl(p: BProc, sym: PSym) =
     # 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
     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:
       # 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])
diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim
index 13eff35be..a8210508c 100644
--- a/compiler/typeallowed.nim
+++ b/compiler/typeallowed.nim
@@ -217,7 +217,7 @@ proc classifyViewTypeAux(marker: var IntSet, t: PType): ViewTypeKind =
   case t.kind
   of tyVar:
     result = mutableView
-  of tyLent, tyVarargs, tyOpenArray:
+  of tyLent, tyOpenArray:
     result = immutableView
   of tyGenericInst, tyDistinct, tyAlias, tyInferred, tySink, tyOwned,
      tyUncheckedArray, tySequence, tyArray, tyRef, tyStatic:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index ad5023aeb..6f81c6a9c 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1807,7 +1807,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
       result.add getNullValue(t[i], info, conf)
   of tySet:
     result = newNodeIT(nkCurly, info, t)
-  of tySequence:
+  of tySequence, tyOpenArray:
     result = newNodeIT(nkBracket, info, t)
   else:
     globalError(conf, info, "cannot create null element for: " & $t.kind)
diff --git a/tests/views/tconst_views.nim b/tests/views/tconst_views.nim
new file mode 100644
index 000000000..d7f1fc481
--- /dev/null
+++ b/tests/views/tconst_views.nim
@@ -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
+