Skip to content

Commit

Permalink
make var/pointer types not match if base type has to be converted (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
metagn authored Sep 18, 2024
1 parent c759d7a commit 1660ddf
Show file tree
Hide file tree
Showing 7 changed files with 394 additions and 5 deletions.
16 changes: 14 additions & 2 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1125,9 +1125,21 @@ proc inferStaticsInRange(c: var TCandidate,
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))

template subtypeCheck() =
if result <= isSubrange and f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
case result
of isIntConv:
result = isNone
of isSubrange:
discard # XXX should be isNone with preview define, warnings
of isConvertible:
if f.last.skipTypes(abstractInst).kind != tyOpenArray:
# exclude var openarray which compiler supports
result = isNone
of isSubtype:
if f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
# compiler can't handle subtype conversions with pointer indirection
result = isNone
else: discard

proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
Expand Down
2 changes: 1 addition & 1 deletion testament/important_packages.nim
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pkg "ssostrings"
pkg "stew"
pkg "stint", "nim c stint.nim"
pkg "strslice"
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
pkg "strunicode", "nimble uninstall -i -y normalize; nimble install -y normalize@#HEAD; nimble install --depsOnly -y; nim c -r --mm:refc src/strunicode.nim"
pkg "supersnappy"
pkg "synthesis"
pkg "taskpools"
Expand Down
4 changes: 2 additions & 2 deletions tests/errmsgs/t22097.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
discard """
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
errormsg: "type mismatch: got <uint8>"
"""

proc toUInt16(x: var uint16) =
discard

var x = uint8(1)
toUInt16 x
toUInt16 x
16 changes: 16 additions & 0 deletions tests/int/twrongexplicitvarconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
discard """
action: reject
nimout: '''
but expression 'int(a)' is immutable, not 'var'
'''
"""

proc `++`(n: var int) =
n += 1

var a: int32 = 15

++int(a) #[tt.Error
^ type mismatch: got <int>]#

echo a
9 changes: 9 additions & 0 deletions tests/int/twrongvarconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
proc `++`(n: var int) =
n += 1

var a: int32 = 15

++a #[tt.Error
^ type mismatch: got <int32>]#

echo a
145 changes: 145 additions & 0 deletions tests/overload/mvaruintconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import
std/[macros, tables, hashes]

export
macros

type
FieldDescription* = object
name*: NimNode
isPublic*: bool
isDiscriminator*: bool
typ*: NimNode
pragmas*: NimNode
caseField*: NimNode
caseBranch*: NimNode

{.push raises: [].}

func isTuple*(t: NimNode): bool =
t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")

macro isTuple*(T: type): untyped =
newLit(isTuple(getType(T)[1]))

proc collectFieldsFromRecList(result: var seq[FieldDescription],
n: NimNode,
parentCaseField: NimNode = nil,
parentCaseBranch: NimNode = nil,
isDiscriminator = false) =
case n.kind
of nnkRecList:
for entry in n:
collectFieldsFromRecList result, entry,
parentCaseField, parentCaseBranch
of nnkRecWhen:
for branch in n:
case branch.kind:
of nnkElifBranch:
collectFieldsFromRecList result, branch[1],
parentCaseField, parentCaseBranch
of nnkElse:
collectFieldsFromRecList result, branch[0],
parentCaseField, parentCaseBranch
else:
doAssert false

of nnkRecCase:
collectFieldsFromRecList result, n[0],
parentCaseField,
parentCaseBranch,
isDiscriminator = true

for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nnkOfBranch:
collectFieldsFromRecList result, branch[^1], n[0], branch
of nnkElse:
collectFieldsFromRecList result, branch[0], n[0], branch
else:
doAssert false

of nnkIdentDefs:
let fieldType = n[^2]
for i in 0 ..< n.len - 2:
var field: FieldDescription
field.name = n[i]
field.typ = fieldType
field.caseField = parentCaseField
field.caseBranch = parentCaseBranch
field.isDiscriminator = isDiscriminator

if field.name.kind == nnkPragmaExpr:
field.pragmas = field.name[1]
field.name = field.name[0]

if field.name.kind == nnkPostfix:
field.isPublic = true
field.name = field.name[1]

result.add field

of nnkSym:
result.add FieldDescription(
name: n,
typ: getType(n),
caseField: parentCaseField,
caseBranch: parentCaseBranch,
isDiscriminator: isDiscriminator)

of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
discard

else:
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr

proc collectFieldsInHierarchy(result: var seq[FieldDescription],
objectType: NimNode) =
var objectType = objectType

objectType.expectKind {nnkObjectTy, nnkRefTy}

if objectType.kind == nnkRefTy:
objectType = objectType[0]

objectType.expectKind nnkObjectTy

var baseType = objectType[1]
if baseType.kind != nnkEmpty:
baseType.expectKind nnkOfInherit
baseType = baseType[0]
baseType.expectKind nnkSym
baseType = getImpl(baseType)
baseType.expectKind nnkTypeDef
baseType = baseType[2]
baseType.expectKind {nnkObjectTy, nnkRefTy}
collectFieldsInHierarchy result, baseType

let recList = objectType[2]
collectFieldsFromRecList result, recList

proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
if typeImpl.isTuple:
for i in 1 ..< typeImpl.len:
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
return

let objectType = case typeImpl.kind
of nnkObjectTy: typeImpl
of nnkTypeDef: typeImpl[2]
else:
macros.error("object type expected", typeImpl)
return

collectFieldsInHierarchy(result, objectType)

macro field*(obj: typed, fieldName: static string): untyped =
newDotExpr(obj, ident fieldName)

proc skipPragma*(n: NimNode): NimNode =
if n.kind == nnkPragmaExpr: n[0]
else: n


{.pop.}
Loading

0 comments on commit 1660ddf

Please sign in to comment.