From fc033ccd24bca9ac6f566c464a722bc610a8b3d8 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Mon, 1 Aug 2022 12:48:41 -0700 Subject: [PATCH] pragmas: type pragmas must follow generic params removed the previous deprecation where pragmas could preceed the generic parameter list in a type definition, eg: ``` type Foo{.somePragma}[T] = ... # now an error type Foo[T] {.somePragma.} = ... # acceptable ``` Due to lots of issues, mostly stylistic, I've pragmas on the RHS of a type definition as legal. Largely because after changing it I realized a more significant rethink of type declaration syntax should cover this in the future. Fixed a number of test failures along the way due to this change. --- compiler/ast/parser.nim | 63 ++++++++++++++------------- compiler/ast/report_enums.nim | 7 +-- compiler/front/cli_reporter.nim | 6 +-- compiler/sem/semdata.nim | 2 +- tests/arc/tweave.nim | 2 +- tests/cpp/tvector_iterator.nim | 4 +- tests/errmsgs/tinvalidinout.nim | 2 +- tests/exception/tcpp_imported_exc.nim | 2 +- tests/generics/tgeneric3.nim | 4 +- tests/iter/titer2.nim | 2 +- tests/misc/tsimplesort.nim | 6 +-- tests/misc/tsizeof.nim | 4 +- 12 files changed, 55 insertions(+), 49 deletions(-) diff --git a/compiler/ast/parser.nim b/compiler/ast/parser.nim index cf2502b12c6..f393f96ea0a 100644 --- a/compiler/ast/parser.nim +++ b/compiler/ast/parser.nim @@ -1987,7 +1987,7 @@ proc parseObject(p: var Parser): PNode = result = newNodeP(nkObjectTy, p) p.getTok result.add if p.tok.tokType == tkCurlyDotLe and p.validInd: - # Deprecated since v0.20.0 + # Deprecated: type declaration syntax needs overhaul to fix this p.localError ParserReport(kind: rparPragmaNotFollowingTypeName) p.parsePragma else: @@ -2063,38 +2063,41 @@ proc parseTypeClass(p: var Parser): PNode = proc parseTypeDef(p: var Parser): PNode = #| - #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux - #| indAndComment? / identVisDot genericParamList? pragma '=' optInd typeDefAux + #| typeDef = identWithPragmaDot '=' optInd typeDefAux + #| indAndComment? / identVisDot genericParamList? pragma? '=' optInd typeDefAux #| indAndComment? result = newNodeP(nkTypeDef, p) - let identifier = p.identVis(allowDot=true) - var identPragma = identifier - var foundPragmas = false - - if p.tok.tokType == tkCurlyDotLe: - let pragma = optPragmas(p) - identPragma = newTreeI(nkPragmaExpr, p.lineInfo, [identifier, pragma]) - foundPragmas = true - - let genericParam = if p.validInd and p.tok.tokType == tkBracketLe: - if foundPragmas: - # Deprecated since v0.20.0 - p.localError ParserReport(kind: rparPragmaBeforeGenericParameters) - parseGenericParamList(p) - else: - p.emptyNode - - if not foundPragmas: - let pragma = optPragmas(p) - if pragma.kind != nkEmpty: - identPragma = newTreeI(nkPragmaExpr, p.lineInfo, [identifier, pragma]) - elif p.tok.tokType == tkCurlyDotLe: - p.localError ParserReport(kind: rparPragmaAlreadyPresent) - - result.add identPragma - result.add genericParam + let + identifier = p.identVis(allowDot=true) + (genericParams, pragmas) = + case p.tok.tokType + of tkBracketLe: + ( + (if p.validInd: parseGenericParamList(p) else: p.emptyNode), + optPragmas(p) + ) + # xxx: should the else/empty generic branch invalid indentation error? + of tkCurlyDotLe: + let res = (p.emptyNode, optPragmas(p)) + + if p.validInd and p.tok.tokType == tkBracketLe: + p.localError ParserReport(kind: rparPragmaBeforeGenericParameters) + + res + of tkEquals: + (p.emptyNode, p.emptyNode) + # parsing for everything after the equals is shared, we do that below + else: + (p.emptyNode, p.emptyNode) # xxx: error? - result.add if p.tok.tokType == tkEquals: + result.add: + if pragmas.kind == nkEmpty: + identifier + else: + newTreeI(nkPragmaExpr, p.lineInfo, [identifier, pragmas]) + result.add genericParams + result.add case p.tok.tokType + of tkEquals: result.info = p.lineInfo p.getTok p.optInd(result) diff --git a/compiler/ast/report_enums.nim b/compiler/ast/report_enums.nim index 5f39fc95397..a785b23eb39 100644 --- a/compiler/ast/report_enums.nim +++ b/compiler/ast/report_enums.nim @@ -220,6 +220,8 @@ type rparPragmaAlreadyPresent rparMisplacedExport + rparPragmaBeforeGenericParameters + # template parser `filter_tmpl.nim` rparTemplMissingEndClose rparTemplInvalidExpression @@ -230,9 +232,8 @@ type # warnings begin rparInconsistentSpacing = "Spacing" - rparEnablePreviewDotOps = "DotLikeOps" rparPragmaNotFollowingTypeName - rparPragmaBeforeGenericParameters + rparEnablePreviewDotOps = "DotLikeOps" # warnings END !! add reports BEFORE the last enum !! rparName = "Name" ## Linter report about used identifier @@ -951,7 +952,7 @@ const rparHintKinds* = {rparName} rparErrorKinds* = {rparInvalidIndentation .. rparInvalidFilter} rparWarningKinds* = { - rparInconsistentSpacing .. rparPragmaBeforeGenericParameters} + rparInconsistentSpacing .. rparEnablePreviewDotOps} #--------------------------------- sem ---------------------------------# repSemKinds* = {low(SemReportKind) .. high(SemReportKind)} diff --git a/compiler/front/cli_reporter.nim b/compiler/front/cli_reporter.nim index 4990c2c8166..ca49e2843fe 100644 --- a/compiler/front/cli_reporter.nim +++ b/compiler/front/cli_reporter.nim @@ -2525,13 +2525,13 @@ proc reportBody*(conf: ConfigRef, r: ParserReport): string = result = "Number of spaces around '$#' is not consistent" of rparEnablePreviewDotOps: - result = "?" + result = "dot-like operators will be parsed differently with `-d:nimPreviewDotLikeOps`" of rparPragmaNotFollowingTypeName: - result = "?" + result = "type pragmas follow the type name; this form of writing pragmas is deprecated" of rparPragmaBeforeGenericParameters: - result = "?" + result = "pragma must come after any generic parameter list" of rparName: result = "?" diff --git a/compiler/sem/semdata.nim b/compiler/sem/semdata.nim index ac15861dba3..81455e69400 100644 --- a/compiler/sem/semdata.nim +++ b/compiler/sem/semdata.nim @@ -1133,7 +1133,7 @@ proc extractPragma(s: PSym): PNode = if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1: # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] result = s.ast[0][1] - doAssert result == nil or result.kind == nkPragma + doAssert result == nil or result.kind in {nkPragma, nkEmpty} proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) = var pragmaNode: PNode diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim index 220d65f97d5..a899c6eb3cb 100644 --- a/tests/arc/tweave.nim +++ b/tests/arc/tweave.nim @@ -1,7 +1,7 @@ discard """ outputsub: '''Success''' - cmd: '''nim c --gc:arc --threads:on $file''' disabled: "bsd" + matrix: "--gc:arc --threads:on" """ # bug #13936 diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim index 4d686955fef..c3886c54769 100644 --- a/tests/cpp/tvector_iterator.nim +++ b/tests/cpp/tvector_iterator.nim @@ -12,8 +12,8 @@ struct Vector { """.} type - Vector {.importcpp: "Vector".} [T] = object - VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object + Vector[T] {.importcpp: "Vector".} = object + VectorIterator[T] {.importcpp: "Vector<'0>::Iterator".} = object var x: VectorIterator[void] diff --git a/tests/errmsgs/tinvalidinout.nim b/tests/errmsgs/tinvalidinout.nim index 1fa3805ee70..268bcf4d516 100644 --- a/tests/errmsgs/tinvalidinout.nim +++ b/tests/errmsgs/tinvalidinout.nim @@ -9,7 +9,7 @@ tinvalidinout.nim(18, 9) Error: the 'in' modifier can be used only with imported """ type - Foo {.header: "foo.h", importcpp.} [in T] = object + Foo[in T] {.header: "foo.h", importcpp.} = object Bar[out X] = object x: int diff --git a/tests/exception/tcpp_imported_exc.nim b/tests/exception/tcpp_imported_exc.nim index 5195b48e7a1..8ab7b87805a 100644 --- a/tests/exception/tcpp_imported_exc.nim +++ b/tests/exception/tcpp_imported_exc.nim @@ -76,7 +76,7 @@ doAssert(getCurrentException() == nil) # raise by pointer and also generic type type - std_vector {.importcpp"std::vector", header"".} [T] = object + std_vector[T] {.importcpp"std::vector", header"".} = object proc newVector[T](len: int): ptr std_vector[T] {.importcpp: "new std::vector<'1>(@)".} proc deleteVector[T](v: ptr std_vector[T]) {.importcpp: "delete @; @ = NIM_NIL;".} diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index 4cb12f91ba6..78183c7ca69 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -12,7 +12,7 @@ import strutils type PNode[T,D] = ref TNode[T,D] - TItem {.acyclic, pure, final, shallow.} [T,D] = object + TItem[T,D] {.acyclic, pure, final, shallow.} = object key: T value: D node: PNode[T,D] @@ -20,7 +20,7 @@ type val_set: bool TItems[T,D] = seq[ref TItem[T,D]] - TNode {.acyclic, pure, final, shallow.} [T,D] = object + TNode[T,D] {.acyclic, pure, final, shallow.} = object slots: TItems[T,D] left: PNode[T,D] count: int32 diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim index f60aed73a0b..975cc786cf0 100644 --- a/tests/iter/titer2.nim +++ b/tests/iter/titer2.nim @@ -17,7 +17,7 @@ type TSlotEnum = enum seEmpty, seFilled, seDeleted TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable* {.final.}[A, B] = object + TTable*[A, B] {.final.} = object data: TKeyValuePairSeq[A, B] counter: int diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim index e4a8e0b3771..39bbe5beb6a 100644 --- a/tests/misc/tsimplesort.nim +++ b/tests/misc/tsimplesort.nim @@ -10,7 +10,7 @@ type TSlotEnum = enum seEmpty, seFilled, seDeleted TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable* {.final, myShallow.}[A, B] = object + TTable*[A, B] {.final, myShallow.} = object data: TKeyValuePairSeq[A, B] counter: int @@ -137,8 +137,8 @@ proc `$`*[A, B](t: TTable[A, B]): string = # ------------------------------ count tables ------------------------------- type - TCountTable* {.final, myShallow.}[ - A] = object ## table that counts the number of each key + TCountTable*[A] {.final, myShallow.} = object + ## table that counts the number of each key data: seq[tuple[key: A, val: int]] counter: int diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 0d96a5e04f6..61d2cbbff78 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -175,7 +175,9 @@ proc transformObjectconfigPacked(arg: NimNode): NimNode = result.add transformObjectconfigPacked(child) proc removeObjectconfig(arg: NimNode): NimNode = - if arg.kind == nnkPragmaExpr and arg[1][0].eqIdent "objectconfig": + if arg.kind == nnkPragmaExpr and + arg[1].kind != nnkEmpty and + arg[1][0].eqIdent "objectconfig": result = arg[0] else: result = copyNimNode(arg)