hacky fix for generic constraints matching
This commit is contained in:
parent
4980ef85e2
commit
ca3a4ce672
8 changed files with 68 additions and 17 deletions
|
|
@ -1937,7 +1937,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||||
# are not transformed correctly. We work around this issue (#411) here
|
# are not transformed correctly. We work around this issue (#411) here
|
||||||
# by ensuring it's no inner proc (owner is a module):
|
# by ensuring it's no inner proc (owner is a module):
|
||||||
if prc.owner.kind == skModule:
|
if prc.skipGenericOwner.kind == skModule:
|
||||||
if (optDeadCodeElim notin gGlobalOptions and
|
if (optDeadCodeElim notin gGlobalOptions and
|
||||||
sfDeadCodeElim notin getModule(prc).flags) or
|
sfDeadCodeElim notin getModule(prc).flags) or
|
||||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
|
|
|
||||||
|
|
@ -861,7 +861,7 @@ proc isActivated(prc: PSym): bool = prc.typ != nil
|
||||||
proc genProc(m: BModule, prc: PSym) =
|
proc genProc(m: BModule, prc: PSym) =
|
||||||
if sfBorrow in prc.flags or not isActivated(prc): return
|
if sfBorrow in prc.flags or not isActivated(prc): return
|
||||||
fillProcLoc(prc)
|
fillProcLoc(prc)
|
||||||
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
|
if sfForward in prc.flags: addForwardedProc(m, prc)
|
||||||
else:
|
else:
|
||||||
genProcNoForward(m, prc)
|
genProcNoForward(m, prc)
|
||||||
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||||
|
|
||||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
if n.sons[bodyPos].kind != nkEmpty:
|
if n.sons[bodyPos].kind != nkEmpty:
|
||||||
|
inc c.InGenericInst
|
||||||
# add it here, so that recursive generic procs are possible:
|
# add it here, so that recursive generic procs are possible:
|
||||||
addDecl(c, result)
|
addDecl(c, result)
|
||||||
pushProcCon(c, result)
|
pushProcCon(c, result)
|
||||||
|
|
@ -107,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
#echo "code instantiated ", result.name.s
|
#echo "code instantiated ", result.name.s
|
||||||
excl(result.flags, sfForward)
|
excl(result.flags, sfForward)
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
|
dec c.InGenericInst
|
||||||
|
|
||||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
for i in countup(0, c.generics.len - 1):
|
for i in countup(0, c.generics.len - 1):
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ type
|
||||||
proxyMatch*: bool # to prevent instantiations
|
proxyMatch*: bool # to prevent instantiations
|
||||||
genericConverter*: bool # true if a generic converter needs to
|
genericConverter*: bool # true if a generic converter needs to
|
||||||
# be instantiated
|
# be instantiated
|
||||||
|
typedescMatched: bool
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -499,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
var x = if a.kind == tyOrdinal: a.sons[0] else: a
|
||||||
|
|
||||||
result = typeRel(c, f.sons[0], x)
|
result = typeRel(c, f.sons[0], x)
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
|
elif a.kind == tyGenericParam:
|
||||||
|
result = isGeneric
|
||||||
of tyForward: InternalError("forward type in typeRel()")
|
of tyForward: InternalError("forward type in typeRel()")
|
||||||
of tyNil:
|
of tyNil:
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
|
|
@ -618,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
of tyGenericParam, tyTypeClass:
|
of tyGenericParam, tyTypeClass:
|
||||||
var x = PType(idTableGet(c.bindings, f))
|
var x = PType(idTableGet(c.bindings, f))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
|
if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
|
||||||
|
# XXX: The fact that generic types currently use tyGenericParam for
|
||||||
|
# their parameters is really a misnomer. tyGenericParam means "match
|
||||||
|
# any value" and what we need is "match any type", which can be encoded
|
||||||
|
# by a tyTypeDesc params. Unfortunately, this requires more substantial
|
||||||
|
# changes in semtypinst and elsewhere.
|
||||||
|
if a.kind == tyTypeDesc:
|
||||||
|
if f.sons == nil or f.sons.len == 0:
|
||||||
|
result = isGeneric
|
||||||
|
else:
|
||||||
|
InternalAssert a.sons != nil and a.sons.len > 0
|
||||||
|
c.typedescMatched = true
|
||||||
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
else:
|
||||||
result = matchTypeClass(c, f, a)
|
result = matchTypeClass(c, f, a)
|
||||||
|
|
||||||
if result == isGeneric:
|
if result == isGeneric:
|
||||||
var concrete = concreteType(c, a)
|
var concrete = concreteType(c, a)
|
||||||
if concrete == nil:
|
if concrete == nil:
|
||||||
|
|
|
||||||
|
|
@ -969,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType =
|
||||||
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
for i in countup(0, typeClass.sonsLen - 1):
|
for i in countup(0, typeClass.sonsLen - 1):
|
||||||
let req = typeClass.sons[i]
|
let req = typeClass.sons[i]
|
||||||
var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or
|
var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind
|
||||||
req.kind == skipTypes(t, {tyGenericInst}).kind
|
|
||||||
if not match:
|
if not match:
|
||||||
case req.kind
|
case req.kind
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
|
|
@ -979,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool =
|
||||||
IdTablePut(bindings, typeClass, t)
|
IdTablePut(bindings, typeClass, t)
|
||||||
of tyTypeClass:
|
of tyTypeClass:
|
||||||
match = matchTypeClass(bindings, req, t)
|
match = matchTypeClass(bindings, req, t)
|
||||||
else: nil
|
elif t.kind == tyTypeClass:
|
||||||
|
match = matchTypeClass(bindings, t, req)
|
||||||
|
|
||||||
elif t.kind in {tyObject} and req.len != 0:
|
elif t.kind in {tyObject} and req.len != 0:
|
||||||
# empty 'object' is fine as constraint in a type class
|
# empty 'object' is fine as constraint in a type class
|
||||||
match = sameType(t, req)
|
match = sameType(t, req)
|
||||||
|
|
@ -1046,7 +1048,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind,
|
||||||
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
|
result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
|
||||||
{tyChar, tyEnum, tyInt..tyUInt64}
|
{tyChar, tyEnum, tyInt..tyFloat128}
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
|
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
|
|
||||||
30
tests/reject/tgenconstraints.nim
Normal file
30
tests/reject/tgenconstraints.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
file: "tgenconstraints.nim"
|
||||||
|
line: 25
|
||||||
|
errormsg: "cannot instantiate T2"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
T1[T: int|string] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
T2[T: Ordinal] = object
|
||||||
|
x: T
|
||||||
|
|
||||||
|
var x1: T1[int]
|
||||||
|
var x2: T1[string]
|
||||||
|
var x3: T2[int]
|
||||||
|
|
||||||
|
proc foo[T](x: T): T2[T] {.discardable.} =
|
||||||
|
var o: T1[T]
|
||||||
|
|
||||||
|
foo(10)
|
||||||
|
|
||||||
|
proc bar(x: string|TNumber): T1[type(x)] {.discardable.} =
|
||||||
|
when type(x) is TNumber:
|
||||||
|
var o: T2[type(x)]
|
||||||
|
|
||||||
|
bar "test"
|
||||||
|
bar 100
|
||||||
|
bar 1.1
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@ discard """
|
||||||
type
|
type
|
||||||
TMyTuple = tuple[a, b: int]
|
TMyTuple = tuple[a, b: int]
|
||||||
|
|
||||||
proc indexOf*(t: typedesc, name: string): int {.compiletime.} =
|
proc indexOf*(t: typedesc, name: string): int =
|
||||||
## takes a tuple and looks for the field by name.
|
## takes a tuple and looks for the field by name.
|
||||||
## returs index of that field.
|
## returs index of that field.
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tfinally.nim"
|
file: "tfinally.nim"
|
||||||
output: '''came
|
output: "came\nhere\n3"
|
||||||
here
|
|
||||||
3'''
|
|
||||||
"""
|
"""
|
||||||
# Test return in try statement:
|
# Test return in try statement:
|
||||||
|
|
||||||
|
|
@ -19,5 +17,3 @@ proc main: int =
|
||||||
|
|
||||||
echo main() #OUT came here 3
|
echo main() #OUT came here 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue