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

fix #6407 SomeFloat and SomeInteger types fails to differentiate in a… #20519

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1874,7 +1874,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
rhsTyp = rhsTyp.lastSon
if lhs.sym.typ.kind == tyAnything:
rhsTyp = rhsTyp.skipIntLit(c.idgen)
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}:
if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual, isTypeClass}:
internalAssert c.config, c.p.resultSym != nil
# Make sure the type is valid for the result variable
typeAllowedCheck(c, n.info, rhsTyp, skResult)
Expand Down
70 changes: 62 additions & 8 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ type
TCandidate* = object
c*: PContext
exactMatches*: int # also misused to prefer iters over procs
typeClassMatches: int
genericMatches: int # also misused to prefer constraints
genericConstrainMatches: int
subtypeMatches: int
intConvMatches: int # conversions to int are not as expensive
convMatches: int
Expand Down Expand Up @@ -182,6 +184,7 @@ proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.convMatches = b.convMatches
a.intConvMatches = b.intConvMatches
a.genericMatches = b.genericMatches
a.typeClassMatches = b.typeClassMatches
a.state = b.state
a.callee = b.callee
a.calleeSym = b.calleeSym
Expand Down Expand Up @@ -282,7 +285,9 @@ proc complexDisambiguation(a, b: PType): int =
proc writeMatches*(c: TCandidate) =
echo "Candidate '", c.calleeSym.name.s, "' at ", c.c.config $ c.calleeSym.info
echo " exact matches: ", c.exactMatches
echo " type class matches: ", c.typeClassMatches
echo " generic matches: ", c.genericMatches
echo " generic constrain matches: ", c.genericConstrainMatches
echo " subtype matches: ", c.subtypeMatches
echo " intconv matches: ", c.intConvMatches
echo " conv matches: ", c.convMatches
Expand All @@ -291,7 +296,19 @@ proc writeMatches*(c: TCandidate) =
proc cmpCandidates*(a, b: TCandidate): int =
result = a.exactMatches - b.exactMatches
if result != 0: return
result = a.genericMatches - b.genericMatches
result = a.typeClassMatches - b.typeClassMatches
if result != 0: return
let ag = a.genericMatches + a.genericConstrainMatches
let bg = b.genericMatches + b.genericConstrainMatches
result = ag - bg
if result != 0: return
result = a.subtypeMatches - b.subtypeMatches
if result != 0: return
result = a.typeClassMatches - b.typeClassMatches
if result != 0: return
let ag = a.genericMatches + a.genericConstrainMatches
let bg = b.genericMatches + b.genericConstrainMatches
result = ag - bg
if result != 0: return
result = a.subtypeMatches - b.subtypeMatches
if result != 0: return
Expand Down Expand Up @@ -1653,7 +1670,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
target.callConv != effectiveArgType.callConv:
return isNone
put(c, f, a)
return isGeneric
return isTypeClass
else:
return isNone

Expand Down Expand Up @@ -2033,7 +2050,8 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
case r
of isConvertible, isIntConv: inc(m.convMatches, convMatch)
of isSubtype, isSubrange: inc(m.subtypeMatches)
of isGeneric, isInferred, isBothMetaConvertible: inc(m.genericMatches)
of isTypeClass: inc(m.typeClassMatches, 2)
of isGeneric, isInferred, isBothMetaConvertible: inc(m.genericMatches, 2)
of isFromIntLit: inc(m.intConvMatches, 256)
of isInferredConvertible:
inc(m.convMatches)
Expand Down Expand Up @@ -2173,9 +2191,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, result, m, c)
else:
inc(m.genericMatches)
of isGeneric:
inc(m.genericMatches)
inc(m.genericMatches, 2)
of isGeneric, isTypeClass:
if r == isGeneric:
inc(m.genericMatches, 2)
else:
inc(m.typeClassMatches, 2)
if arg.typ == nil:
result = arg
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
Expand Down Expand Up @@ -2204,7 +2225,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
of isNone:
# do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
if a.kind in {tyProxy, tyUnknown}:
inc(m.genericMatches)
inc(m.genericMatches, 2)
m.fauxMatch = a.kind
return arg
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
Expand All @@ -2216,7 +2237,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
params = nkFormalParams.newTree(p.emptyNode), name = p.emptyNode, pattern = p.emptyNode,
genericParams = p.emptyNode, pragmas = p.emptyNode, exceptions = p.emptyNode), {})
if f.kind == tyBuiltInTypeClass:
inc m.genericMatches
inc m.typeClassMatches, 2
put(m, f, lifted.typ)
inc m.convMatches
return implicitConv(nkHiddenStdConv, f, lifted, m, c)
Expand Down Expand Up @@ -2395,6 +2416,36 @@ proc findFirstArgBlock(m: var TCandidate, n: PNode): int =
result = a2
else: break

proc checkGenericConstraint(m: var TCandidate; t: PType; typ: PType): bool =
if typ == nil: return
case t.kind
of tyOr:
for s in t.sons:
if m.checkGenericConstraint(s, typ):
return true
of tyAnd:
for s in t.sons:
if m.checkGenericConstraint(s, typ):
result = true
else:
result = false
break
of tyNot:
if t[0].kind == tyGenericParam:
let tt = PType(idTableGet(m.bindings, t[0]))
if tt != nil:
return not m.checkGenericConstraint(tt, typ)
return not m.checkGenericConstraint(t[0], typ)
of tyBuiltInTypeClass:
return m.checkGenericConstraint(t[0], typ)
of tyTypeDesc:
return m.checkGenericConstraint(t[0], typ[0])
of tyGenericParam:
if t.len == 0: return true
result = m.checkGenericConstraint(t[0], typ)
else:
return t.kind == typ.kind

proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var IntSet) =

template noMatch() =
Expand All @@ -2421,6 +2472,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
elif not (isLValue(c, n, isOutParam(formal.typ))):
m.firstMismatch.kind = kVarNeeded
noMatch()
if formal.typ.kind == tyGenericParam and formal.typ.len > 0:
if m.checkGenericConstraint(formal.typ, n.typ):
inc(m.genericConstrainMatches, 1)

m.state = csMatch # until proven otherwise
m.firstMismatch = MismatchInfo()
Expand Down
1 change: 1 addition & 0 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type
isInferred, # generic proc was matched against a concrete type
isInferredConvertible, # same as above, but requiring proc CC conversion
isGeneric,
isTypeClass,
isFromIntLit, # conversion *from* int literal; proven safe
isEqual

Expand Down
10 changes: 5 additions & 5 deletions lib/pure/json.nim
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
assert(obj.kind == JObject)
obj.fields[key] = val

proc `%`*(o: enum): JsonNode =
## Construct a JsonNode that represents the specified enum value as a
## string. Creates a new `JString JsonNode`.
result = %($o)

proc `%`*[T: object](o: T): JsonNode =
## Construct JsonNode from tuples and objects.
result = newJObject()
Expand All @@ -402,11 +407,6 @@ proc `%`*(o: ref object): JsonNode =
else:
result = %(o[])

proc `%`*(o: enum): JsonNode =
## Construct a JsonNode that represents the specified enum value as a
## string. Creates a new `JString JsonNode`.
result = %($o)

proc toJsonImpl(x: NimNode): NimNode =
case x.kind
of nnkBracket: # array
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/strformat.nim
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ proc formatValue*(result: var string; value: string; specifier: string) =
setLen(value, runeOffset(value, spec.precision))
result.add alignString(value, spec.minimumWidth, spec.align, spec.fill)

proc formatValue[T: not SomeInteger](result: var string; value: T; specifier: string) =
proc formatValue[T: not SomeNumber](result: var string; value: T; specifier: string) =
mixin `$`
formatValue(result, $value, specifier)

Expand Down
10 changes: 10 additions & 0 deletions tests/generics/t13549.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

proc foo[T](x: T):int = 1

proc foo[T: tuple](x: T):int = 2

doAssert foo((1, 2, 3)) == 2

type Obj = object
proc foo(x: object):int = 3
doAssert foo(Obj()) == 3
14 changes: 14 additions & 0 deletions tests/generics/t18314.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
discard """
disabled: true
"""

type
A = ref object of RootObj
B = ref object of A
C = ref object of B

proc foo[T: A](a: T):int = 1
proc foo[T: B](b: T):int = 2

var c = C()
doAssert foo(c) == 2
13 changes: 13 additions & 0 deletions tests/generics/t4084.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
discard """
disabled: true
"""

type
Image[T: int32|int64] = object
data: seq[T]

proc newImage[T](w, h: int): ref Image[T] =
new(result)
result.data = newSeq[T](w * h)

var i = newImage[string](320, 200)
12 changes: 12 additions & 0 deletions tests/generics/t6407.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
discard """
action: compile
"""

proc foo[T6407: SomeFloat](y: T6407):int = 0

proc foo[T6407: SomeInteger](y: T6407):int = 1

proc boo[T6407](x: T6407):int =
foo[T6407](x)

doAssert boo(1) == 1
10 changes: 10 additions & 0 deletions tests/generics/t6407_2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
discard """
action: compile
"""

proc sort[T: uint8|char|byte](c: T) = discard
proc sort[T: bool](c: T) = discard

proc sorted[T](c: T): T = sort[T](c)

doAssert sorted(true) == false