diff options
author | Araq <rumpf_a@web.de> | 2014-02-13 21:30:11 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-13 21:30:11 +0100 |
commit | 5d4c0487055d3099d85243dab7b02886a01412b1 (patch) | |
tree | 8155235650f1d4baf77f6eeb368228747f145ce3 | |
parent | f637c36a7a145ad2f90e82f79331c97666bcecd0 (diff) | |
parent | 7a3106d6597e755b94d8623dc173f0275f81f69b (diff) | |
download | Nim-5d4c0487055d3099d85243dab7b02886a01412b1.tar.gz |
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r-- | compiler/sem.nim | 1 | ||||
-rw-r--r-- | compiler/semdata.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 9 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 77 | ||||
-rw-r--r-- | compiler/vm.nim | 2 | ||||
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | lib/pure/collections/sets.nim | 4 | ||||
-rw-r--r-- | tests/collections/tsets.nim | 17 | ||||
-rw-r--r-- | tests/generics/tinferredgenericprocs.nim | 20 | ||||
-rw-r--r-- | tests/sets/tsets_lt.nim | 12 |
10 files changed, 115 insertions, 31 deletions
diff --git a/compiler/sem.nim b/compiler/sem.nim index 00ac79716..845d4ae71 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -332,6 +332,7 @@ proc myOpen(module: PSym): PPassContext = c.semOperand = semOperand c.semConstBoolExpr = semConstBoolExpr c.semOverloadedCall = semOverloadedCall + c.semGenerateInstance = generateInstance c.semTypeNode = semTypeNode pushProcCon(c, module) pushOwner(c.module) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index c9d95e1bf..0bc52d6b7 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -81,6 +81,8 @@ type semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, filter: TSymKinds): PNode {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} + semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, + info: TLineInfo): PSym includedFiles*: TIntSet # used to detect recursive include files userPragmas*: TStrTable evalContext*: PEvalContext diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a8a16672d..3fe1367ec 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -204,7 +204,14 @@ proc semConv(c: PContext, n: PNode): PNode = if not isSymChoice(op): let status = checkConvertible(c, result.typ, op.typ) case status - of convOK: discard + of convOK: + # handle SomeProcType(SomeGenericProc) + # XXX: This needs fixing. checkConvertible uses typeRel internally, but + # doesn't bother to perform the work done in paramTypeMatchAux/fitNode + # so we are redoing the typeRel work here. Why does semConv exist as a + # separate proc from fitNode? + if op.kind == nkSym and op.sym.isGenericRoutine: + result.sons[1] = fitNode(c, result.typ, result.sons[1]) of convNotNeedeed: message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 335ceafeb..227228f6e 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -51,6 +51,8 @@ type isSubtype, isSubrange, # subrange of the wanted type; no type conversion # but apart from that counts as ``isSubtype`` + isInferred, # generic proc was matched against a concrete type + isInferredConvertible, # same as above, but requiring proc CC conversion isGeneric, isFromIntLit, # conversion *from* int literal; proven safe isEqual @@ -338,10 +340,40 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = proc allowsNil(f: PType): TTypeRelation {.inline.} = result = if tfNotNil notin f.flags: isSubtype else: isNone -proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = - proc inconsistentVarTypes(f, a: PType): bool {.inline.} = - result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) +proc inconsistentVarTypes(f, a: PType): bool {.inline.} = + result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar) + +proc procParamTypeRel(c: var TCandidate, f, a: PType, + result: var TTypeRelation) = + var + m: TTypeRelation + f = f + + if a.isMetaType: + if f.isMetaType: + # we are matching a generic proc (as proc param) + # to another generic type appearing in the proc + # sigunature. there is a change that the target + # type is already fully-determined, so we are + # going to try resolve it + f = generateTypeInstance(c.c, c.bindings, c.call.info, f) + if f == nil or f.isMetaType: + # no luck resolving the type, so the inference fails + result = isNone + return + let reverseRel = typeRel(c, a, f) + if reverseRel == isGeneric: + m = isInferred + else: + m = typeRel(c, f, a) + + if m <= isSubtype or inconsistentVarTypes(f, a): + result = isNone + return + else: + result = minRel(m, result) +proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = case a.kind of tyProc: if sonsLen(f) != sonsLen(a): return @@ -350,18 +382,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = result = isEqual # start with maximum; also correct for no # params at all for i in countup(1, sonsLen(f)-1): - var m = typeRel(c, f.sons[i], a.sons[i]) - if m <= isSubtype or inconsistentVarTypes(f.sons[i], a.sons[i]): - return isNone - else: result = minRel(m, result) + procParamTypeRel(c, f.sons[i], a.sons[i], result) if f.sons[0] != nil: if a.sons[0] != nil: - var m = typeRel(c, f.sons[0], a.sons[0]) - # Subtype is sufficient for return types! - if m < isSubtype or inconsistentVarTypes(f.sons[0], a.sons[0]): - return isNone - elif m == isSubtype: result = isConvertible - else: result = minRel(m, result) + procParamTypeRel(c, f.sons[0], a.sons[0], result) else: return isNone elif a.sons[0] != nil: @@ -376,7 +400,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = elif f.callConv != a.callConv: # valid to pass a 'nimcall' thingie to 'closure': if f.callConv == ccClosure and a.callConv == ccDefault: - result = isConvertible + result = if result != isInferred: isConvertible + else: isInferredConvertible else: return isNone when useEffectSystem: @@ -402,18 +427,8 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc matchUserTypeClass*(c: PContext, m: var TCandidate, ff, a: PType): TTypeRelation = - #if f.n == nil: - # let r = typeRel(m, f, a) - # return if r == isGeneric: arg else: nil - var body = ff.skipTypes({tyUserTypeClassInst}) - # var prev = PType(idTableGet(m.bindings, f)) - # if prev != nil: - # if sameType(prev, a): return arg - # else: return nil - - # pushInfoContext(arg.info) openScope(c) inc c.inTypeClass @@ -462,7 +477,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, else: discard return isGeneric - # put(m.bindings, f, a) proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # typeRel can be used to establish various relationships between types: @@ -988,7 +1002,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, arg = argSemantized argType = argType c = m.c - + if tfHasStatic in fMaybeStatic.flags: # XXX: When implicit statics are the default # this will be done earlier - we just have to @@ -1022,6 +1036,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, inc(m.subtypeMatches) #result = copyTree(arg) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + of isInferred, isInferredConvertible: + var prc = if arg.kind in nkLambdaKinds: arg[0].sym + else: arg.sym + let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info) + result = newSymNode(inferred, arg.info) + if r == isInferredConvertible: + result = implicitConv(nkHiddenStdConv, f, result, m, c) of isGeneric: inc(m.genericMatches) if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: @@ -1035,10 +1056,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = argOrig else: result = copyTree(arg) - result.typ = getInstantiatedType(c, arg, m, f) + result.typ = getInstantiatedType(c, arg, m, f) # BUG: f may not be the right key! if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) # BUGFIX: use ``result.typ`` and not `f` here of isFromIntLit: # too lazy to introduce another ``*matches`` field, so we conflate diff --git a/compiler/vm.nim b/compiler/vm.nim index 10ac7aaaf..81e712047 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -441,7 +441,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = decodeBImm(nkIntLit) #assert regs[rb].kind == nkBracket # also used by mNLen: - regs[ra].intVal = regs[rb].skipMeta.len - imm + regs[ra].intVal = regs[rb].skipMeta.safeLen - imm of opcLenStr: decodeBImm(nkIntLit) if regs[rb].kind == nkNilLit: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 585ccf869..d14822974 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -516,7 +516,7 @@ proc last*(node: PNimrodNode): PNimrodNode {.compileTime.} = node[node.high] const - RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda} + RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef} AtomicNodes* = {nnkNone..nnkNilLit} CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index e6ab617e5..ad3fe7218 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -241,3 +241,7 @@ proc `<=`*[A](s, t: TSet[A]): bool = proc `==`*[A](s, t: TSet[A]): bool = s.counter == t.counter and s <= t + +proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] = + result = initSet[B]() + for item in data: result.incl(op(item)) diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim new file mode 100644 index 000000000..656c5b3f2 --- /dev/null +++ b/tests/collections/tsets.nim @@ -0,0 +1,17 @@ +discard """ + output: '''true +true''' +""" + +import sets +var + a = initSet[int]() + b = initSet[int]() + c = initSet[string]() + +for i in 0..5: a.incl(i) +for i in 1..6: b.incl(i) +for i in 0..5: c.incl($i) + +echo map(a, proc(x: int): int = x + 1) == b +echo map(a, proc(x: int): string = $x) == c diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim new file mode 100644 index 000000000..ac445fd32 --- /dev/null +++ b/tests/generics/tinferredgenericprocs.nim @@ -0,0 +1,20 @@ +discard """ + output: '''123 +1 +2 +3''' +""" + +# https://github.com/Araq/Nimrod/issues/797 +proc foo[T](s:T):string = $s + +type IntStringProc = proc(x: int): string + +var f1 = IntStringProc(foo) +var f2: proc(x: int): string = foo +var f3: IntStringProc = foo + +echo f1(1), f2(2), f3(3) + +for x in map([1,2,3], foo): echo x + diff --git a/tests/sets/tsets_lt.nim b/tests/sets/tsets_lt.nim new file mode 100644 index 000000000..6d0b3a60c --- /dev/null +++ b/tests/sets/tsets_lt.nim @@ -0,0 +1,12 @@ +discard """ + output: '''true +true +true''' +""" + +var s, s1: set[char] +s = {'a'..'d'} +s1 = {'a'..'c'} +echo s1 < s +echo s1 * s == {'a'..'c'} +echo s1 <= s |