From cbf66e99a85551021d768aa81858f9d7b6f55d6f Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 31 Aug 2016 02:17:14 +0300 Subject: [PATCH] Working test cases for the sophisticated matrix library example from the manual Fixed the dot operator when used within return types (see tgenericdotrettype) Fixed the matching of generic concepts aliases used with the implicit generics style --- compiler/semexprs.nim | 28 +++++++++++----- compiler/semtypes.nim | 10 +++--- compiler/semtypinst.nim | 2 ++ compiler/sigmatch.nim | 48 ++++++++++++++++----------- compiler/types.nim | 18 +++++----- compiler/vmgen.nim | 3 +- doc/manual/generics.txt | 30 ++++++++++++----- tests/concepts/matrix.nim | 15 +++++++++ tests/concepts/matrixalgo.nim | 28 ++++++++++++++++ tests/concepts/tmatrixconcept.nim | 22 +++++++++--- tests/concepts/tmatrixlib.nim | 31 +++++++++++++++++ tests/generics/tgenericdotrettype.nim | 29 ++++++++++++++++ 12 files changed, 211 insertions(+), 53 deletions(-) create mode 100644 tests/concepts/matrix.nim create mode 100644 tests/concepts/matrixalgo.nim create mode 100644 tests/concepts/tmatrixlib.nim create mode 100644 tests/generics/tgenericdotrettype.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b5e9e6dc4..9d0f4aef1 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -911,8 +911,7 @@ proc makeDeref(n: PNode): PNode = t = skipTypes(baseTyp, {tyGenericInst, tyAlias}) const - tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass, - tyUserTypeClass, tyUserTypeClassInst} + tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass} tyDotOpTransparent = {tyVar, tyPtr, tyRef, tyAlias} proc readTypeParameter(c: PContext, typ: PType, @@ -1107,6 +1106,23 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var ty = n.sons[0].typ var f: PSym = nil result = nil + + template tryReadingGenericParam(t: PType) = + case t.kind + of tyTypeParamsHolders: + return readTypeParameter(c, t, i, n.info) + of tyUserTypeClasses: + if t.isResolvedUserTypeClass: + return readTypeParameter(c, t, i, n.info) + else: + n.typ = makeTypeFromExpr(c, copyTree(n)) + return n + of tyGenericParam: + n.typ = makeTypeFromExpr(c, copyTree(n)) + return n + else: + discard + if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone): if ty.kind == tyTypeDesc: ty = ty.base ty = ty.skipTypes(tyDotOpTransparent) @@ -1124,8 +1140,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = markUsed(n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) return - of tyTypeParamsHolders: - return readTypeParameter(c, ty, i, n.info) of tyObject, tyTuple: if ty.n != nil and ty.n.kind == nkRecList: let field = lookupInRecord(ty.n, i) @@ -1134,8 +1148,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = n.typ.n = copyTree(n) return n else: - # echo "TYPE FIELD ACCESS" - # debug ty + tryReadingGenericParam(ty) return # XXX: This is probably not relevant any more # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim": @@ -1178,8 +1191,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # we didn't find any field, let's look for a generic param if result == nil: let t = n.sons[0].typ.skipTypes(tyDotOpTransparent) - if t.kind in tyTypeParamsHolders: - result = readTypeParameter(c, t, i, n.info) + tryReadingGenericParam(t) proc dotTransformation(c: PContext, n: PNode): PNode = if isSymChoice(n.sons[1]): diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 204641b74..42ffaa5fa 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -845,9 +845,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, for i in 0 .. paramType.sonsLen - 2: if paramType.sons[i].kind == tyStatic: - var x = copyNode(ast.emptyNode) - x.typ = paramType.sons[i] - result.rawAddSon makeTypeFromExpr(c, x) # aka 'tyUnknown' + var staticCopy = paramType.sons[i].exactReplica + staticCopy.flags.incl tfInferrableStatic + result.rawAddSon staticCopy else: result.rawAddSon newTypeS(tyAnything, c) @@ -891,7 +891,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, allowMetaTypes = true) result = liftingWalk(expanded, true) - of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: + of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true)) of tyGenericParam: @@ -1357,6 +1357,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: result = semGeneric(c, n, s, prev) of nkDotExpr: let typeExpr = semExpr(c, n) + if typeExpr.typ.kind == tyFromExpr: + return typeExpr.typ if typeExpr.typ.kind != tyTypeDesc: localError(n.info, errTypeExpected) result = errorType(c) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ac8a5ff82..fddcc7a24 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -404,6 +404,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = case t.kind of tyGenericInvocation: result = handleGenericInvocation(cl, t) + if result.lastSon.kind == tyUserTypeClass: + result.kind = tyUserTypeClassInst of tyGenericBody: localError(cl.info, errCannotInstantiateX, typeToString(t)) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 5a6f4e015..a40f8ee66 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -613,26 +613,34 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, template paramSym(kind): untyped = newSym(kind, typeParamName, Concept.sym, Concept.sym.info) - case typ.kind - of tyStatic: - param = paramSym skConst - param.typ = typ.exactReplica - if typ.n == nil: - param.typ.flags.incl tfInferrableStatic - else: - param.ast = typ.n - of tyUnknown: - param = paramSym skVar - param.typ = typ.exactReplica - else: - param = paramSym skType - param.typ = if typ.isMetaType: - c.newTypeWithSons(tyInferred, @[typ]) - else: - makeTypeDesc(c, typ) + block addTypeParam: + for prev in typeParams: + if prev[1].id == typ.id: + param = paramSym prev[0].kind + param.typ = prev[0].typ + break addTypeParam + case typ.kind + of tyStatic: + param = paramSym skConst + param.typ = typ.exactReplica + if typ.n == nil: + param.typ.flags.incl tfInferrableStatic + else: + param.ast = typ.n + of tyUnknown: + param = paramSym skVar + param.typ = typ.exactReplica + else: + param = paramSym skType + param.typ = if typ.isMetaType: + c.newTypeWithSons(tyInferred, @[typ]) + else: + makeTypeDesc(c, typ) + + typeParams.safeAdd((param, typ)) + addDecl(c, param) - typeParams.safeAdd((param, typ)) for param in Concept.n[0]: var @@ -682,7 +690,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, diagnostics.add msg var checkedBody = c.semTryExpr(c, body.copyTree, flags) - + if collectDiagnostics: writelnHook = oldWriteHook for msg in diagnostics: m.diagnostics.safeAdd msg @@ -696,7 +704,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, ff.sym.info, ff) + result = generateTypeInstance(c, m.bindings, Concept.sym.info, ff) else: result = copyType(ff, ff.owner, true) diff --git a/compiler/types.nim b/compiler/types.nim index 65eb6de61..3f84548a1 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -183,7 +183,7 @@ proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, if result: return if not containsOrIncl(marker, t.id): case t.kind - of tyGenericInst, tyGenericBody, tyAlias: + of tyGenericInst, tyGenericBody, tyAlias, tyInferred: result = iterOverTypeAux(marker, lastSon(t), iter, closure) else: for i in countup(0, sonsLen(t) - 1): @@ -1320,6 +1320,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = if result < 0: return if a < maxAlign: a = maxAlign result = align(result, a) + of tyInferred: + if typ.len > 1: + result = computeSizeAux(typ.lastSon, a) of tyGenericInst, tyDistinct, tyGenericBody, tyAlias: result = computeSizeAux(lastSon(typ), a) of tyTypeClasses: @@ -1351,18 +1354,17 @@ proc getSize(typ: PType): BiggestInt = if result < 0: internalError("getSize: " & $typ.kind) proc containsGenericTypeIter(t: PType, closure: RootRef): bool = - if t.kind == tyStatic: + case t.kind + of tyStatic: return t.n == nil - - if t.kind == tyTypeDesc: + of tyTypeDesc: if t.base.kind == tyNone: return true if containsGenericTypeIter(t.base, closure): return true return false - - if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}: + of GenericTypes + tyTypeClasses + {tyFromExpr}: return true - - return false + else: + return false proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 125fe8ae0..c7d9be48c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1678,7 +1678,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = elif sfImportc in s.flags: c.importcSym(n.info, s) genLit(c, n, dest) of skConst: - gen(c, s.ast, dest) + let constVal = if s.ast != nil: s.ast else: s.typ.n + gen(c, constVal, dest) of skEnumField: if dest < 0: dest = c.getTemp(n.typ) if s.position >= low(int16) and s.position <= high(int16): diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index f4afa0d11..d1af6d962 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -305,6 +305,9 @@ The concept types can be parametric just like the regular generic types: .. code-block:: nim ### matrixalgo.nim + + import typetraits + type AnyMatrix*[R, C: static[int]; T] = concept m, var mvar, type M M.ValueType is T @@ -314,9 +317,13 @@ The concept types can be parametric just like the regular generic types: m[int, int] is T mvar[int, int] = T + type TransposedType = StripGenericParams(M)[C, R, T] + AnySquareMatrix*[N: static[int], T] = AnyMatrix[N, N, T] - proc transpose*[R, C, T](m: AnyMatrix[R, C, T]): m.type.basis[C, R, T] = + AnyTransform3D* = AnyMatrix[4, 4, float] + + proc transposed*(m: AnyMatrix): m.TransposedType = for r in 0 ..