Skip to content

Commit ac20804

Browse files
committed
Fixes #25340
1 parent a061f02 commit ac20804

File tree

5 files changed

+97
-2
lines changed

5 files changed

+97
-2
lines changed

compiler/ccgexprs.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3317,8 +3317,9 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
33173317
cCast(ptrType(destType),
33183318
wrapPar(cAddr(wrapPar(val))))),
33193319
a.storage)
3320-
elif p.module.compileToCpp:
3320+
elif p.module.compileToCpp or isImportedType(src):
33213321
# C++ implicitly downcasts for us
3322+
# importc types don't have a Sup field, so we must cast
33223323
expr(p, arg, d)
33233324
else:
33243325
var a: TLoc = initLocExpr(p, arg)

compiler/semtypes.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
10141014
proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int,
10151015
obj: PType, n: PNode, isPartial = false, innerObj: PType = nil): bool =
10161016
if ((not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags)) or
1017-
(innerObj != nil and obj.sym.id == innerObj.sym.id):
1017+
(innerObj != nil and obj.sym != nil and innerObj.sym != nil and obj.sym.id == innerObj.sym.id):
10181018
localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'")
10191019
result = false
10201020
elif obj.kind == tyObject:

compiler/semtypinst.nim

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,19 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
499499
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
500500
result.flags = result.flags + newbody.flags - tfInstClearedFlags
501501

502+
# Propagate importc from generic body to instantiated body (for computed type aliases)
503+
if body.sym != nil and sfImportc in body.sym.flags:
504+
if newbody.sym != nil and sfImportc notin newbody.sym.flags:
505+
incl(newbody.sym.flagsImpl, sfImportc)
506+
newbody.sym.locImpl.snippet = body.sym.loc.snippet # copy the C name
507+
elif newbody.sym.isNil and newbody.kind == tyObject:
508+
# Computed type alias returned an anonymous object type - create a symbol for it
509+
let s = newSym(skType, body.sym.name, cl.c.idgen, body.sym.owner, cl.info)
510+
incl(s.flagsImpl, sfImportc)
511+
s.locImpl.snippet = body.sym.loc.snippet
512+
s.typ = newbody
513+
newbody.sym = s
514+
502515
setToPreviousLayer(cl.typeMap)
503516

504517
# This is actually wrong: tgeneric_closure fails with this line:

compiler/sigmatch.nim

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
17021702
if hasCovariance:
17031703
continue
17041704

1705+
# Fallback for computed generic type aliases (bug #25340):
1706+
# Check if the aliased types (last elements) have inheritance relationship
1707+
let aLast = roota.last
1708+
let fLast = rootf.last
1709+
if aLast.kind == tyObject and fLast.kind == tyObject and trIsOutParam notin flags:
1710+
let depth = isObjectSubtype(c, aLast, fLast, nil)
1711+
if depth > 0:
1712+
inc c.inheritancePenalty, depth + ord(c.inheritancePenalty < 0)
1713+
return isSubtype
17051714
return isNone
17061715
if prev == nil: put(c, f, a)
17071716
else:

tests/typerel/t25340.nim

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import macros
2+
3+
block:
4+
type
5+
JSObj {.inheritable, pure.} = object
6+
JSExternObjBase {.inheritable, pure, noinit, importc: "int", bycopy.} = object
7+
HTMLElement = object of JSObj
8+
Document = object of HTMLElement
9+
10+
macro parent(t: typedesc): untyped =
11+
let n = t.getType()[1]
12+
if $n == "JSObj":
13+
return ident"JSExternObjBase"
14+
else:
15+
let imp = n.getTypeImpl()
16+
imp.expectKind(nnkObjectTy)
17+
let base = imp[1][0]
18+
result = newTree(nnkObjectTy,
19+
newEmptyNode(),
20+
newTree(nnkOfInherit,
21+
newTree(nnkBracketExpr, ident"JSExternObj", base)),
22+
newEmptyNode())
23+
24+
type
25+
JSExternObj[T] {.noinit, importc: "int", bycopy.} = parent(T)
26+
27+
var a: JSExternObj[JSObj]
28+
var d: JSExternObj[Document]
29+
a = d
30+
proc p(a: JSExternObj[JSObj]) =
31+
discard
32+
p(d)
33+
34+
assert JSExternObj[Document] is JSExternObj[HTMLElement]
35+
assert JSExternObj[HTMLElement] is JSExternObj[JSObj]
36+
assert JSExternObj[Document] is JSExternObj[JSObj]
37+
38+
block:
39+
type
40+
JSObj {.inheritable.} = object
41+
JSExternObjBase {.inheritable, pure.} = object
42+
HTMLElement = object of JSObj
43+
Document = object of HTMLElement
44+
45+
macro parent(t: typedesc): untyped =
46+
let n = t.getType()[1]
47+
if $n == "JSObj":
48+
return ident"JSExternObjBase"
49+
else:
50+
let imp = n.getTypeImpl()
51+
imp.expectKind(nnkObjectTy)
52+
let base = imp[1][0]
53+
result = newTree(nnkObjectTy,
54+
newEmptyNode(),
55+
newTree(nnkOfInherit,
56+
newTree(nnkBracketExpr, ident"JSExternObj", base)),
57+
newEmptyNode())
58+
59+
type
60+
JSExternObj[T] = parent(T)
61+
62+
var a: JSExternObj[JSObj]
63+
var d: JSExternObj[Document]
64+
a = d
65+
proc p(a: JSExternObj[JSObj]) =
66+
discard
67+
p(d)
68+
69+
assert JSExternObj[Document] is JSExternObj[HTMLElement]
70+
assert JSExternObj[HTMLElement] is JSExternObj[JSObj]
71+
assert JSExternObj[Document] is JSExternObj[JSObj]
72+

0 commit comments

Comments
 (0)