summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorandri lim <jangko128@gmail.com>2017-03-15 03:40:09 +0700
committerAndreas Rumpf <rumpf_a@web.de>2017-03-14 21:40:09 +0100
commit0ff1190fe704179745e4303a2e09ba8baf566c01 (patch)
tree4a7006dc78608310c214cffb6415d15e3f9024fc
parent976095c894934a0311e75ae9ac45ad09395f1842 (diff)
downloadNim-0ff1190fe704179745e4303a2e09ba8baf566c01.tar.gz
fixes #5264 (#5520); inheriting from generic object
-rw-r--r--compiler/semtypes.nim35
-rw-r--r--tests/types/tparameterizedparent0.nim15
-rw-r--r--tests/types/tparameterizedparent1.nim14
-rw-r--r--tests/types/tparameterizedparent2.nim77
-rw-r--r--tests/types/tparameterizedparent3.nim15
-rw-r--r--tests/types/tparameterizedparent4.nim30
6 files changed, 184 insertions, 2 deletions
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 7877a26a9..bffa12f33 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -622,6 +622,13 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       else: addSon(a, newSymNode(f))
       styleCheckDef(f)
     if a.kind != nkEmpty: addSon(father, a)
+  of nkSym:
+    # this branch only valid during generic object
+    # with parameterized parent second check.
+    # There is no branch validity check here
+    if containsOrIncl(check, n.sym.name.id):
+      localError(n.info, errAttemptToRedefine, n.sym.name.s)
+    addSon(father, n)
   of nkEmpty: discard
   else: illFormedAst(n)
 
@@ -673,8 +680,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
       localError(n.info, errIllegalRecursionInTypeX, "object")
     else:
       var concreteBase = skipGenericInvocation(base)
-      if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
-        addInheritedFields(c, check, pos, concreteBase)
+      if concreteBase.kind in {tyObject, tyGenericParam} and tfFinal notin concreteBase.flags:
+        if concreteBase.kind == tyObject:
+          addInheritedFields(c, check, pos, concreteBase)
       else:
         if concreteBase.kind != tyError:
           localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
@@ -1045,6 +1053,23 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
 proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
   result = semTypeNode(c, n, nil)
 
+proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
+  var check = initIntSet()
+  var realBase = t.sons[0]
+  var pos = 0
+  var base = skipTypesOrNil(realBase, skipPtrs)
+  if base.isNil:
+    localError(n.info, errIllegalRecursionInTypeX, "object")
+  else:
+    var concreteBase = skipGenericInvocation(base)
+    if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
+      addInheritedFields(c, check, pos, concreteBase)
+    else:
+      if concreteBase.kind != tyError:
+        localError(n.info, errInheritanceOnlyWithNonFinalObjects)
+  var newf = newNodeI(nkRecList, n.info)
+  semRecordNodeAux(c, t.n, check, pos, newf, t)
+
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
   if s.typ == nil:
     localError(n.info, "cannot instantiate the '$1' $2" %
@@ -1107,6 +1132,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
         result = instGenericContainer(c, n.info, result,
                                       allowMetaTypes = false)
 
+  # special check for generic object with
+  # parameterized parent
+  let tx = result.skipTypes(abstractPtrs)
+  if tx != result and tx.kind == tyObject and tx.sons[0] != nil:
+    semObjectTypeForInheritedGenericInst(c, n, tx)
+
 proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
   var n = semExprWithType(c, n, {efDetermineType})
   if n.typ.kind == tyTypeDesc:
diff --git a/tests/types/tparameterizedparent0.nim b/tests/types/tparameterizedparent0.nim
new file mode 100644
index 000000000..1b72a4e21
--- /dev/null
+++ b/tests/types/tparameterizedparent0.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tparameterizedparent0.nim"
+  line: 14
+  errormsg: "inheritance only works with non-final objects"
+"""
+# bug #5264
+type
+  Kapal* = enum
+    Besar
+
+  Apple[T] = object of T
+    color: int
+
+var x = Apple[Kapal](color: 13)
+echo x
diff --git a/tests/types/tparameterizedparent1.nim b/tests/types/tparameterizedparent1.nim
new file mode 100644
index 000000000..24fb9a565
--- /dev/null
+++ b/tests/types/tparameterizedparent1.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "tparameterizedparent1.nim"
+  line: 14
+  errormsg: "inheritance only works with non-final objects"
+"""
+# bug #5264
+type
+  FruitBase = object
+    color: int
+
+  Apple[T] = object of T
+    width: int
+
+var x: Apple[FruitBase]
diff --git a/tests/types/tparameterizedparent2.nim b/tests/types/tparameterizedparent2.nim
new file mode 100644
index 000000000..999db2ac5
--- /dev/null
+++ b/tests/types/tparameterizedparent2.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''(width: 11, color: 13)
+(width: 15, weight: 13, taste: 11, color: 14)
+(width: 17, color: 16)
+(width: 12.0, taste: yummy, color: 13)
+(width: 0, tast_e: 0.0, kind: Smooth, skin: 1.5, color: 12)'''
+"""
+# bug #5264
+type
+  Texture = enum
+    Smooth
+    Coarse
+
+  FruitBase = object of RootObj
+    color: int
+
+  Level2Fruit = object of FruitBase
+    taste: int
+
+  AppleBanana = object of Level2Fruit
+    weight: int
+
+  BaseFruit[T] = object of RootObj
+    color: T
+
+  Apple[T] = object of T
+    width: int
+
+  Peach[X, T, Y] = object of T
+    width: X
+    taste: Y
+
+  Lemon[T] = object of T
+    width: int
+    tast_e: float64
+    case kind: Texture
+    of Smooth:
+      skin: float64
+    of Coarse:
+      grain: int
+
+var x: Apple[FruitBase]
+x.color = 13
+x.width = 11
+echo x
+
+proc setColor(self: var FruitBase, c: int) =
+  self.color = c
+
+proc setTaste[T](self: var Apple[T], c: int) =
+  self.taste = c
+
+#proc setColor[T](self: var BaseFruit[T], c: int) =
+#  self.color = c
+
+var y: Apple[AppleBanana]
+y.setColor(14)
+y.setTaste(11)
+y.weight = 13
+y.width = 15
+echo y
+
+var w: Apple[BaseFruit[int]]
+w.width = 17
+w.color = 16
+echo w
+
+var z: Peach[float64, BaseFruit[int], string]
+z.width = 12
+z.taste = "yummy"
+#z.setColor(13) #this trigger other bug
+z.color = 13
+echo z
+
+var k = Lemon[FruitBase](kind: Smooth, skin: 1.5)
+k.setColor(12)
+echo k
diff --git a/tests/types/tparameterizedparent3.nim b/tests/types/tparameterizedparent3.nim
new file mode 100644
index 000000000..3fc83cb4d
--- /dev/null
+++ b/tests/types/tparameterizedparent3.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tparameterizedparent3.nim"
+  line: 13
+  errormsg: "redefinition of 'color'"
+"""
+# bug #5264
+type
+  FruitBase = object of RootObj
+    color: int
+
+  Apple[T] = object of T
+    width: int
+    color: int
+
+var x: Apple[FruitBase]
diff --git a/tests/types/tparameterizedparent4.nim b/tests/types/tparameterizedparent4.nim
new file mode 100644
index 000000000..fa8b525c1
--- /dev/null
+++ b/tests/types/tparameterizedparent4.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tparameterizedparent4.nim"
+  line: 23
+  errormsg: "redefinition of 'grain'"
+"""
+# bug #5264
+type
+  Texture = enum
+    Smooth
+    Coarse
+
+  FruitBase = object of RootObj
+    color: int
+    grain: string
+
+  Apple[T] = object of T
+    width: int
+    tast_e: float64
+    case kind: Texture
+    of Smooth:
+      skin: float64
+    of Coarse:
+      grain: int
+
+proc setColor(self: var FruitBase, c: int) =
+  self.color = c
+
+var x = Apple[FruitBase](kind: Smooth, skin: 1.5)
+x.setColor(14)
+echo x