diff options
-rw-r--r-- | compiler/semexprs.nim | 4 | ||||
-rw-r--r-- | compiler/semstmts.nim | 6 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 42 | ||||
-rw-r--r-- | tests/concepts/tmapconcept.nim | 102 | ||||
-rw-r--r-- | tests/concepts/tstackconcept.nim | 2 |
5 files changed, 145 insertions, 11 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b3fe83ed8..d81abe20e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -319,11 +319,11 @@ proc isOpImpl(c: PContext, n: PNode): PNode = result = newIntNode(nkIntLit, 0) else: var rhsOrigType = n[2].typ - discard inferTypeClassParam(c, t1, rhsOrigType) var t2 = rhsOrigType.skipTypes({tyTypeDesc}) maybeLiftType(t2, c, n.info) var m: TCandidate initCandidate(c, m, t2) + discard inferTypeClassParam(m, t1, rhsOrigType) let match = typeRel(m, t2, t1) >= isSubtype # isNone result = newIntNode(nkIntLit, ord(match)) @@ -912,8 +912,6 @@ const tyTypeParamsHolders = {tyGenericInst, tyUserTypeClassInst, tyCompositeTypeClass} tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias} - - proc readTypeParameter(c: PContext, typ: PType, paramName: PIdent, info: TLineInfo): PNode = let ty = if typ.kind in {tyGenericInst, tyUserTypeClassInst}: typ.skipGenericAlias diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 9a1850932..33b684e91 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1631,8 +1631,12 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard else: localError(n.sons[j].info, errStmtInvalidAfterReturn) else: discard - if result.len == 1 and result.sons[0].kind != nkDefer: + + if result.len == 1 and + c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list + result.sons[0].kind != nkDefer: result = result.sons[0] + when defined(nimfix): if result.kind == nkCommentStmt and not result.comment.isNil and not (result.comment[0] == '#' and result.comment[1] == '#'): diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f819af13d..3dede8b6f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -645,7 +645,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, put(m.bindings, p[1], p[0].typ) if ff.kind == tyUserTypeClassInst: - result = generateTypeInstance(c, m.bindings, m.call.info, ff) + result = generateTypeInstance(c, m.bindings, ff.sym.info, ff) else: result = copyType(ff, ff.owner, true) @@ -1403,13 +1403,34 @@ proc skipToInferrableParam(tt: PType): PType = return nil -proc inferTypeClassParam*(c: PContext, f, a: PType): bool = +proc inferTypeClassParam*(m: var TCandidate, f, a: PType): bool = + var c = m.c if c.inTypeClass == 0: return false var inferrableType = a.skipToInferrableParam if inferrableType == nil: return false - inferrableType.assignType f + var inferAs = f + + case f.kind + of tyGenericParam: + var prev = PType(idTableGet(m.bindings, f)) + if prev != nil: inferAs = prev + + of tyFromExpr: + let computedType = tryResolvingStaticExpr(m, f.n).typ + case computedType.kind + of tyTypeDesc: + inferAs = computedType.base + of tyStatic: + inferAs = computedType + else: + localError(f.n.info, errTypeExpected) + + else: + discard + + inferrableType.assignType inferAs return true proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, @@ -1420,7 +1441,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argType = argType c = m.c - if inferTypeClassParam(c, f, argType): + if inferTypeClassParam(m, f, argType): return argSemantized if tfHasStatic in fMaybeStatic.flags: @@ -1448,9 +1469,18 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, arg.typ.n = evaluated argType = arg.typ - var a = argType - var r = typeRel(m, f, a) + var + useTypeLoweringRuleInTypeClass = c.inTypeClass > 0 and + not m.isNoCall and + f.kind != tyTypeDesc + a = if useTypeLoweringRuleInTypeClass: + argType.skipTypes({tyTypeDesc, tyFieldAccessor}) + else: + argType + + r = typeRel(m, f, a) + if r != isNone and m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: # XXX: duplicating this is ugly, but we cannot (!) move this diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim new file mode 100644 index 000000000..81caed7c6 --- /dev/null +++ b/tests/concepts/tmapconcept.nim @@ -0,0 +1,102 @@ +discard """ +output: '''10 +10 +nil +1''' +msg: ''' +K=string V=int +K=int64 V=string +K=int V=int +''' +""" + +import tables, typetraits + +template ok(check) = assert check +template no(check) = assert(not check) + +type + Enumerable[T] = concept e + for v in e: + v is T + + Map[K, V] = concept m, var mvar + m[K] is V + mvar[K] = V + m.contains(K) is bool + m.valuesSeq is Enumerable[V] + + TreeMap[K, V] = object + root: int + + SparseSeq = object + data: seq[int] + + JudyArray = object + data: SparseSeq + +static: + ok seq[int] is Enumerable[int] + ok seq[string] is Enumerable + ok seq[int] is Enumerable[SomeNumber] + ok SparseSeq.data is Enumerable + no seq[string] is Enumerable[int] + no int is Enumerable + no int is Enumerable[int] + +# Complete the map concept implementation for the Table type +proc valuesSeq[K, V](t: Table[K, V]): seq[V] = + result = @[] + for k, v in t: + result.add v + +# Map concept inplementation for TreeMap +proc valuesSeq(t: TreeMap): array[1, TreeMap.V] = + var v: t.V + result = [v] + +proc contains[K, V](t: TreeMap[K, V], key: K): bool = true + +proc `[]=`[K, V](t: var TreeMap[K, V], key: K, val: V) = discard +proc `[]`(t: TreeMap, key: t.K): TreeMap.V = discard + +# Map concept implementation for the non-generic JudyArray +proc valuesSeq(j: JudyArray): SparseSeq = j.data + +proc contains(t: JudyArray, key: int): bool = true + +proc `[]=`(t: var JudyArray, key, val: int) = discard +proc `[]`(t: JudyArray, key: int): int = discard + +iterator items(s: SparseSeq): int = + for i in s.data: yield i + +# Generic proc defined over map +proc getFirstValue[K,V](m : Map[K,V]): V = + static: echo "K=", K.name, " V=", V.name + + for i in m.valuesSeq: + return i + + raise newException(RangeError, "no values") + +proc useConceptProcInGeneric[K, V](t: Table[K, V]): V = + return t.getFirstValue + +var t = initTable[string, int]() +t["test"] = 10 + +echo t.getFirstValue +echo t.useConceptProcInGeneric + +var tm = TreeMap[int64, string](root: 0) +echo getFirstValue(tm) + +var j = JudyArray(data: SparseSeq(data: @[1, 2, 3])) +echo getFirstValue(j) + +static: + ok Table[int, float] is Map + ok Table[int, string] is Map[SomeNumber, string] + no JudyArray is Map[string, int] + diff --git a/tests/concepts/tstackconcept.nim b/tests/concepts/tstackconcept.nim index 11d6505cf..b6ead2c2b 100644 --- a/tests/concepts/tstackconcept.nim +++ b/tests/concepts/tstackconcept.nim @@ -46,7 +46,7 @@ proc implicitGeneric(s: var Stack): auto = static: echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name - echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", s.ValueTypeName + echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName return s.pop() |