hacky fix for generic constraints matching

This commit is contained in:
Zahary Karadjov 2013-08-15 22:55:11 +03:00
commit ca3a4ce672
8 changed files with 68 additions and 17 deletions

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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:

View file

@ -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:

View 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

View file

@ -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

View file

@ -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