diff options
author | Zahary Karadjov <zahary@gmail.com> | 2013-08-15 22:55:11 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2013-08-19 01:48:25 +0300 |
commit | ca3a4ce6721c87cfcbb9eb02002ecf8aeb89233c (patch) | |
tree | 76a5fd56fc4ae9cd459d4703c3287b9a088aecb2 | |
parent | 4980ef85e254178747dc8ea9fd59b058d33b2df1 (diff) | |
download | Nim-ca3a4ce6721c87cfcbb9eb02002ecf8aeb89233c.tar.gz |
hacky fix for generic constraints matching
-rw-r--r-- | compiler/ccgexprs.nim | 4 | ||||
-rw-r--r-- | compiler/cgen.nim | 4 | ||||
-rw-r--r-- | compiler/seminst.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 23 | ||||
-rw-r--r-- | compiler/types.nim | 10 | ||||
-rw-r--r-- | tests/reject/tgenconstraints.nim | 30 | ||||
-rw-r--r-- | tests/run/tfieldindex.nim | 2 | ||||
-rw-r--r-- | tests/run/tfinally.nim | 10 |
8 files changed, 68 insertions, 17 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index bb1035ab6..635756220 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1932,12 +1932,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = nil of nkPragma: genPragma(p, n) of nkProcDef, nkMethodDef, nkConverterDef: - if (n.sons[genericParamsPos].kind == nkEmpty): + if (n.sons[genericParamsPos].kind == nkEmpty): var prc = n.sons[namePos].sym # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # 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 sfDeadCodeElim notin getModule(prc).flags) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 787a2143f..0c3f2da84 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -861,8 +861,8 @@ proc isActivated(prc: PSym): bool = prc.typ != nil proc genProc(m: BModule, prc: PSym) = if sfBorrow in prc.flags or not isActivated(prc): return fillProcLoc(prc) - if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc) - else: + if sfForward in prc.flags: addForwardedProc(m, prc) + else: genProcNoForward(m, prc) if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and generatedHeader != nil and lfNoDecl notin prc.loc.Flags: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 47d889a60..601072833 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -87,6 +87,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) proc instantiateBody(c: PContext, n: PNode, result: PSym) = if n.sons[bodyPos].kind != nkEmpty: + inc c.InGenericInst # add it here, so that recursive generic procs are possible: addDecl(c, result) pushProcCon(c, result) @@ -107,6 +108,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) = #echo "code instantiated ", result.name.s excl(result.flags, sfForward) popProcCon(c) + dec c.InGenericInst proc fixupInstantiatedSymbols(c: PContext, s: PSym) = for i in countup(0, c.generics.len - 1): diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 41268d6d0..626d16d64 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -38,6 +38,7 @@ type proxyMatch*: bool # to prevent instantiations genericConverter*: bool # true if a generic converter needs to # be instantiated + typedescMatched: bool inheritancePenalty: int # to prefer closest father object type TTypeRelation* = enum # order is important! @@ -499,8 +500,11 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyOrdinal: if isOrdinalType(a): var x = if a.kind == tyOrdinal: a.sons[0] else: a + result = typeRel(c, f.sons[0], x) if result < isGeneric: result = isNone + elif a.kind == tyGenericParam: + result = isGeneric of tyForward: InternalError("forward type in typeRel()") of tyNil: if a.kind == f.kind: result = isEqual @@ -618,7 +622,24 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyGenericParam, tyTypeClass: var x = PType(idTableGet(c.bindings, f)) if x == nil: - result = matchTypeClass(c, f, a) + 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) + if result == isGeneric: var concrete = concreteType(c, a) if concrete == nil: diff --git a/compiler/types.nim b/compiler/types.nim index b8aaed45e..2564741d8 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -969,8 +969,8 @@ proc skipGenericAlias*(t: PType): PType = proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool = for i in countup(0, typeClass.sonsLen - 1): let req = typeClass.sons[i] - var match = req.kind == skipTypes(t, {tyGenericInst, tyRange}).kind or - req.kind == skipTypes(t, {tyGenericInst}).kind + var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind + if not match: case req.kind of tyGenericBody: @@ -979,7 +979,9 @@ proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool = IdTablePut(bindings, typeClass, t) of tyTypeClass: 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: # empty 'object' is fine as constraint in a type class match = sameType(t, req) @@ -1046,7 +1048,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, lastSon(t), kind, flags) of tyRange: result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in - {tyChar, tyEnum, tyInt..tyUInt64} + {tyChar, tyEnum, tyInt..tyFloat128} of tyOpenArray, tyVarargs: result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags) of tySequence: diff --git a/tests/reject/tgenconstraints.nim b/tests/reject/tgenconstraints.nim new file mode 100644 index 000000000..e32aa877b --- /dev/null +++ b/tests/reject/tgenconstraints.nim @@ -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 + diff --git a/tests/run/tfieldindex.nim b/tests/run/tfieldindex.nim index 3ffa65e58..f0674af54 100644 --- a/tests/run/tfieldindex.nim +++ b/tests/run/tfieldindex.nim @@ -5,7 +5,7 @@ discard """ type 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. ## returs index of that field. var diff --git a/tests/run/tfinally.nim b/tests/run/tfinally.nim index 273aac72b..16fb3e7da 100644 --- a/tests/run/tfinally.nim +++ b/tests/run/tfinally.nim @@ -1,8 +1,6 @@ discard """ file: "tfinally.nim" - output: '''came -here -3''' + output: "came\nhere\n3" """ # Test return in try statement: @@ -14,10 +12,8 @@ proc main: int = echo("came") return 2 finally: - echo("here ") + echo("here") return 3 - -echo main() #OUT came here 3 - +echo main() #OUT came here 3 |