Skip to content

Commit 894eee0

Browse files
metagnnarimiran
authored andcommitted
make var/pointer types not match if base type has to be converted (#24130)
split again from #24038, fixes status-im/nimbus-eth2#6554 (comment) `var`/pointer types are no longer implicitly convertible to each other if their element types either: * require an int conversion or another conversion operation as long as it's not to `openarray`, * are subtypes with pointer indirection, Previously any conversion below a subrange match would match if the element type wasn't a pointer type, then it would error later in `analyseIfAddressTaken`. Different from #24038 in that the preview define that made subrange matches also fail to match is removed for a simpler diff so that it can be backported. (cherry picked from commit 1660ddf)
1 parent 4b8b8fb commit 894eee0

File tree

6 files changed

+393
-4
lines changed

6 files changed

+393
-4
lines changed

compiler/sigmatch.nim

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -984,9 +984,21 @@ proc inferStaticsInRange(c: var TCandidate,
984984
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
985985

986986
template subtypeCheck() =
987-
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {
988-
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
987+
case result
988+
of isIntConv:
989989
result = isNone
990+
of isSubrange:
991+
discard # XXX should be isNone with preview define, warnings
992+
of isConvertible:
993+
if f.lastSon.skipTypes(abstractInst).kind != tyOpenArray:
994+
# exclude var openarray which compiler supports
995+
result = isNone
996+
of isSubtype:
997+
if f.lastSon.skipTypes(abstractInst).kind in {
998+
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
999+
# compiler can't handle subtype conversions with pointer indirection
1000+
result = isNone
1001+
else: discard
9901002

9911003
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
9921004
# this proc is always called for a pair of matching types

tests/errmsgs/t22097.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
discard """
2-
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
2+
errormsg: "type mismatch: got <uint8>"
33
"""
44

55
proc toUInt16(x: var uint16) =
66
discard
77

88
var x = uint8(1)
9-
toUInt16 x
9+
toUInt16 x
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
discard """
2+
action: reject
3+
nimout: '''
4+
but expression 'int(a)' is immutable, not 'var'
5+
'''
6+
"""
7+
8+
proc `++`(n: var int) =
9+
n += 1
10+
11+
var a: int32 = 15
12+
13+
++int(a) #[tt.Error
14+
^ type mismatch: got <int>]#
15+
16+
echo a

tests/int/twrongvarconv.nim

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
proc `++`(n: var int) =
2+
n += 1
3+
4+
var a: int32 = 15
5+
6+
++a #[tt.Error
7+
^ type mismatch: got <int32>]#
8+
9+
echo a

tests/overload/mvaruintconv.nim

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import
2+
std/[macros, tables, hashes]
3+
4+
export
5+
macros
6+
7+
type
8+
FieldDescription* = object
9+
name*: NimNode
10+
isPublic*: bool
11+
isDiscriminator*: bool
12+
typ*: NimNode
13+
pragmas*: NimNode
14+
caseField*: NimNode
15+
caseBranch*: NimNode
16+
17+
{.push raises: [].}
18+
19+
func isTuple*(t: NimNode): bool =
20+
t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
21+
22+
macro isTuple*(T: type): untyped =
23+
newLit(isTuple(getType(T)[1]))
24+
25+
proc collectFieldsFromRecList(result: var seq[FieldDescription],
26+
n: NimNode,
27+
parentCaseField: NimNode = nil,
28+
parentCaseBranch: NimNode = nil,
29+
isDiscriminator = false) =
30+
case n.kind
31+
of nnkRecList:
32+
for entry in n:
33+
collectFieldsFromRecList result, entry,
34+
parentCaseField, parentCaseBranch
35+
of nnkRecWhen:
36+
for branch in n:
37+
case branch.kind:
38+
of nnkElifBranch:
39+
collectFieldsFromRecList result, branch[1],
40+
parentCaseField, parentCaseBranch
41+
of nnkElse:
42+
collectFieldsFromRecList result, branch[0],
43+
parentCaseField, parentCaseBranch
44+
else:
45+
doAssert false
46+
47+
of nnkRecCase:
48+
collectFieldsFromRecList result, n[0],
49+
parentCaseField,
50+
parentCaseBranch,
51+
isDiscriminator = true
52+
53+
for i in 1 ..< n.len:
54+
let branch = n[i]
55+
case branch.kind
56+
of nnkOfBranch:
57+
collectFieldsFromRecList result, branch[^1], n[0], branch
58+
of nnkElse:
59+
collectFieldsFromRecList result, branch[0], n[0], branch
60+
else:
61+
doAssert false
62+
63+
of nnkIdentDefs:
64+
let fieldType = n[^2]
65+
for i in 0 ..< n.len - 2:
66+
var field: FieldDescription
67+
field.name = n[i]
68+
field.typ = fieldType
69+
field.caseField = parentCaseField
70+
field.caseBranch = parentCaseBranch
71+
field.isDiscriminator = isDiscriminator
72+
73+
if field.name.kind == nnkPragmaExpr:
74+
field.pragmas = field.name[1]
75+
field.name = field.name[0]
76+
77+
if field.name.kind == nnkPostfix:
78+
field.isPublic = true
79+
field.name = field.name[1]
80+
81+
result.add field
82+
83+
of nnkSym:
84+
result.add FieldDescription(
85+
name: n,
86+
typ: getType(n),
87+
caseField: parentCaseField,
88+
caseBranch: parentCaseBranch,
89+
isDiscriminator: isDiscriminator)
90+
91+
of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
92+
discard
93+
94+
else:
95+
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
96+
97+
proc collectFieldsInHierarchy(result: var seq[FieldDescription],
98+
objectType: NimNode) =
99+
var objectType = objectType
100+
101+
objectType.expectKind {nnkObjectTy, nnkRefTy}
102+
103+
if objectType.kind == nnkRefTy:
104+
objectType = objectType[0]
105+
106+
objectType.expectKind nnkObjectTy
107+
108+
var baseType = objectType[1]
109+
if baseType.kind != nnkEmpty:
110+
baseType.expectKind nnkOfInherit
111+
baseType = baseType[0]
112+
baseType.expectKind nnkSym
113+
baseType = getImpl(baseType)
114+
baseType.expectKind nnkTypeDef
115+
baseType = baseType[2]
116+
baseType.expectKind {nnkObjectTy, nnkRefTy}
117+
collectFieldsInHierarchy result, baseType
118+
119+
let recList = objectType[2]
120+
collectFieldsFromRecList result, recList
121+
122+
proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
123+
if typeImpl.isTuple:
124+
for i in 1 ..< typeImpl.len:
125+
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
126+
return
127+
128+
let objectType = case typeImpl.kind
129+
of nnkObjectTy: typeImpl
130+
of nnkTypeDef: typeImpl[2]
131+
else:
132+
macros.error("object type expected", typeImpl)
133+
return
134+
135+
collectFieldsInHierarchy(result, objectType)
136+
137+
macro field*(obj: typed, fieldName: static string): untyped =
138+
newDotExpr(obj, ident fieldName)
139+
140+
proc skipPragma*(n: NimNode): NimNode =
141+
if n.kind == nnkPragmaExpr: n[0]
142+
else: n
143+
144+
145+
{.pop.}

0 commit comments

Comments
 (0)