diff options
author | metagn <metagngn@gmail.com> | 2023-04-11 10:23:41 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-11 09:23:41 +0200 |
commit | 1bb117cd7a49954832d21e6a1502492770acb77b (patch) | |
tree | 299cbbc13c72d8f0e3844a1c9770874a25050a67 /compiler | |
parent | 420b0c14eb0b82e05873191b277e889f95bc802b (diff) | |
download | Nim-1bb117cd7a49954832d21e6a1502492770acb77b.tar.gz |
`proc` typeclass accounts for `iterator`, call conventions + `nil` fix + document typeclass AST (#21629)
* test fix #16546 #16548 + another issue * please don't tell me other packages do this * fix CI + test typeclass callconv pragma * better logic in parser * docs and changelog
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/parser.nim | 7 | ||||
-rw-r--r-- | compiler/semexprs.nim | 1 | ||||
-rw-r--r-- | compiler/semtypes.nim | 30 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 19 | ||||
-rw-r--r-- | compiler/typesrenderer.nim | 3 |
5 files changed, 37 insertions, 23 deletions
diff --git a/compiler/parser.nim b/compiler/parser.nim index e921bf1f4..c62cb0d8e 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1204,8 +1204,11 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode = result[bodyPos] = parseStmt(p) else: result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info) - if hasSignature: - result.add(params) + if hasSignature or pragmas.kind != nkEmpty: + if hasSignature: + result.add(params) + else: # pragmas but no param list, implies typeclass with pragmas + result.add(p.emptyNode) if kind == nkFuncDef: parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead") result.add(pragmas) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7ba4099d3..a765a92b9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -469,6 +469,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = res = t.kind == tyProc and t.callConv == ccClosure of "iterator": + # holdover from when `is iterator` didn't work let t = skipTypes(t1, abstractRange) res = t.kind == tyProc and t.callConv == ccClosure and diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f2846377c..d86f5ddb2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2054,25 +2054,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkOutTy: result = semVarOutType(c, n, prev, {tfIsOutParam}) of nkDistinctTy: result = semDistinct(c, n, prev) of nkStaticTy: result = semStaticType(c, n[0], prev) - of nkIteratorTy: - if n.len == 0: + of nkProcTy, nkIteratorTy: + if n.len == 0 or n[0].kind == nkEmpty: + # 0 length or empty param list with possible pragmas imply typeclass result = newTypeS(tyBuiltInTypeClass, c) let child = newTypeS(tyProc, c) - child.flags.incl tfIterator + var symKind: TSymKind + if n.kind == nkIteratorTy: + child.flags.incl tfIterator + if n.len > 0 and n[1].kind != nkEmpty and n[1].len > 0: + # typeclass with pragma + let symKind = if n.kind == nkIteratorTy: skIterator else: skProc + # dummy symbol for `pragma`: + var s = newSymS(symKind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c) + s.typ = child + # for now only call convention pragmas supported in proc typeclass + pragma(c, s, n[1], {FirstCallConv..LastCallConv}) result.addSonSkipIntLit(child, c.idgen) else: - result = semProcTypeWithScope(c, n, prev, skIterator) - if result.kind == tyProc: - result.flags.incl(tfIterator) - if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline): - result.callConv = ccInline - else: - result.callConv = ccClosure - of nkProcTy: - if n.len == 0: - result = newConstraint(c, tyProc) - else: result = semProcTypeWithScope(c, n, prev, skProc) + if n.kind == nkIteratorTy and result.kind == tyProc: + result.flags.incl(tfIterator) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 0c6456e68..92971b072 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -624,6 +624,9 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if f.len != a.len: return result = isEqual # start with maximum; also correct for no # params at all + + if f.flags * {tfIterator} != a.flags * {tfIterator}: + return isNone template checkParam(f, a) = result = minRel(result, procParamTypeRel(c, f, a)) @@ -1636,13 +1639,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyBuiltInTypeClass: considerPreviousT: - let targetKind = f[0].kind + let target = f[0] + let targetKind = target.kind let effectiveArgType = a.skipTypes({tyRange, tyGenericInst, tyBuiltInTypeClass, tyAlias, tySink, tyOwned}) - let typeClassMatches = targetKind == effectiveArgType.kind and - not effectiveArgType.isEmptyContainer - if typeClassMatches or - (targetKind in {tyProc, tyPointer} and effectiveArgType.kind == tyNil): + if targetKind == effectiveArgType.kind: + if effectiveArgType.isEmptyContainer: + return isNone + if targetKind == tyProc: + if target.flags * {tfIterator} != effectiveArgType.flags * {tfIterator}: + return isNone + if tfExplicitCallConv in target.flags and + target.callConv != effectiveArgType.callConv: + return isNone put(c, f, a) return isGeneric else: diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index f59f63659..b5bceccc2 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -64,9 +64,8 @@ proc renderType(n: PNode, toNormalize: bool): string = result = "ptr" of nkProcTy: assert n.len != 1 - if n.len > 1: + if n.len > 1 and n[0].kind == nkFormalParams: let params = n[0] - assert params.kind == nkFormalParams assert params.len > 0 result = "proc(" for i in 1..<params.len: result.add(renderType(params[i], toNormalize) & ',') |