Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #7906, array and openarray arg vs. ptr/ref generic #7909

Merged
merged 2 commits into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,12 @@ proc commonType*(x, y: PType): PType =
a = a.lastSon.skipTypes({tyGenericInst})
b = b.lastSon.skipTypes({tyGenericInst})
if a.kind == tyObject and b.kind == tyObject:
result = commonSuperclass(a, b, k)
result = commonSuperclass(a, b)
# this will trigger an error later:
if result.isNil or result == a: return x
if result == b: return y
if k != tyNone:
# bug #7906
if k != tyNone and x.kind != tyGenericInst:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here explaining your reasoning. It seems fishy, why is tyGenericInst harmful here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add a comment.

the reason is

type
   GenericObject[T] = object
   GenericRefObject[T] = ref object
   
var a = GenericRefObject[int]          # tyGenericInst of ref object
var b = new(ref GenericObject[int]) # tyRef of tyGenericInst

from user perpective, a and b should be not too different, but inside the compiler, they are two different types.

so, if it already a tyGenericInst of ref object, it would be wrong to add more tyRef in front of it.
additional tyRef in the next compiler phase will generate ill formed AST.

let r = result
result = newType(k, r.owner)
result.addSonSkipIntLit(r)
Expand Down
4 changes: 2 additions & 2 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ proc inheritanceDiff*(a, b: PType): int =
inc(result)
result = high(int)

proc commonSuperclass*(a, b: PType, k: TTypeKind): PType =
proc commonSuperclass*(a, b: PType): PType =
# quick check: are they the same?
if sameObjectTypes(a, b): return a

Expand All @@ -1063,7 +1063,7 @@ proc commonSuperclass*(a, b: PType, k: TTypeKind): PType =
y = skipTypes(y, skipPtrs)
if ancestors.contains(y.id):
# bug #7818, defer the previous skipTypes
if k in {tyRef, tyPtr}: t = y
if t.kind != tyGenericInst: t = y
return t
y = y.sons[0]

Expand Down
141 changes: 114 additions & 27 deletions tests/array/t7818.nim
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
discard """
msg: '''BracketExpr
Sym "array"
Infix
Ident ".."
IntLit 0
IntLit 2
BracketExpr
Sym "Vehicle"
Sym "int"
---------
BracketExpr
Sym "array"
Infix
Ident ".."
IntLit 0
IntLit 2
BracketExpr
Sym "Vehicle"
Sym "int"
---------'''
output: "OK"
"""

# bug #7818
Expand All @@ -34,12 +15,118 @@ type
Bike[T] = object of Vehicle[T]

macro peek(n: typed): untyped =
echo getTypeImpl(n).treeRepr
echo "---------"
let val = getTypeImpl(n).treeRepr
newLit(val)

block test_t7818:
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)

let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)

block test_t7906_1:
proc init(x: typedesc, y: int): ref x =
result = new(ref x)
result.tire = y

var v = init(Vehicle[int], 3)
var c = init(Car[int], 4)
var b = init(Bike[int], 2)

let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)

block test_t7906_2:
var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)

let y = peek([c.addr, b.addr, v.addr])
let z = peek([v.addr, c.addr, b.addr])
doAssert(y == z)

block test_t7906_3:
type
Animal[T] = object of RootObj
hair: T
Mammal[T] = object of Animal[T]
Monkey[T] = object of Mammal[T]

var v = Animal[int](hair: 3)
var c = Mammal[int](hair: 4)
var b = Monkey[int](hair: 2)

let z = peek([c.addr, b.addr, v.addr])
let y = peek([v.addr, c.addr, b.addr])
doAssert(y == z)

type
Fruit[T] = ref object of RootObj
color: T
Apple[T] = ref object of Fruit[T]
Banana[T] = ref object of Fruit[T]

proc testArray[T](x: array[3, Fruit[T]]): string =
result = ""
for c in x:
result.add $c.color

proc testOpenArray[T](x: openArray[Fruit[T]]): string =
result = ""
for c in x:
result.add $c.color

block test_t7906_4:
var v = Fruit[int](color: 3)
var c = Apple[int](color: 4)
var b = Banana[int](color: 2)

let y = peek([c, b, v])
let z = peek([v, c, b])
doAssert(y == z)

block test_t7906_5:
var a = Fruit[int](color: 1)
var b = Apple[int](color: 2)
var c = Banana[int](color: 3)

doAssert(testArray([a, b, c]) == "123")
doAssert(testArray([b, c, a]) == "231")

doAssert(testOpenArray([a, b, c]) == "123")
doAssert(testOpenArray([b, c, a]) == "231")

doAssert(testOpenArray(@[a, b, c]) == "123")
doAssert(testOpenArray(@[b, c, a]) == "231")

proc testArray[T](x: array[3, ptr Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire

proc testOpenArray[T](x: openArray[ptr Vehicle[T]]): string =
result = ""
for c in x:
result.add $c.tire

block test_t7906_6:
var u = Vehicle[int](tire: 1)
var v = Bike[int](tire: 2)
var w = Car[int](tire: 3)

doAssert(testArray([u.addr, v.addr, w.addr]) == "123")
doAssert(testArray([w.addr, u.addr, v.addr]) == "312")

doAssert(testOpenArray([u.addr, v.addr, w.addr]) == "123")
doAssert(testOpenArray([w.addr, u.addr, v.addr]) == "312")

doAssert(testOpenArray(@[u.addr, v.addr, w.addr]) == "123")
doAssert(testOpenArray(@[w.addr, u.addr, v.addr]) == "312")

echo "OK"

var v = Vehicle[int](tire: 3)
var c = Car[int](tire: 4)
var b = Bike[int](tire: 2)

peek([c, b, v])
peek([v, c, b])