Skip to content

Commit

Permalink
Merge #400
Browse files Browse the repository at this point in the history
400: pragmas: type pragmas must follow generic params r=saem a=saem

## Summary

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
```

## Details

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.

Co-authored-by: Saem Ghani <saemghani+github@gmail.com>
  • Loading branch information
bors[bot] and saem authored Aug 7, 2022
2 parents ecc5673 + edc3656 commit 983a875
Show file tree
Hide file tree
Showing 14 changed files with 59 additions and 53 deletions.
63 changes: 33 additions & 30 deletions compiler/ast/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
7 changes: 4 additions & 3 deletions compiler/ast/report_enums.nim
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ type
rparPragmaAlreadyPresent
rparMisplacedExport

rparPragmaBeforeGenericParameters

# template parser `filter_tmpl.nim`
rparTemplMissingEndClose
rparTemplInvalidExpression
Expand All @@ -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
Expand Down Expand Up @@ -951,7 +952,7 @@ const
rparHintKinds* = {rparName}
rparErrorKinds* = {rparInvalidIndentation .. rparInvalidFilter}
rparWarningKinds* = {
rparInconsistentSpacing .. rparPragmaBeforeGenericParameters}
rparInconsistentSpacing .. rparEnablePreviewDotOps}

#--------------------------------- sem ---------------------------------#
repSemKinds* = {low(SemReportKind) .. high(SemReportKind)}
Expand Down
6 changes: 3 additions & 3 deletions compiler/front/cli_reporter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "?"
Expand Down
2 changes: 1 addition & 1 deletion compiler/sem/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,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
Expand Down
2 changes: 1 addition & 1 deletion tests/arc/tweave.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
discard """
outputsub: '''Success'''
cmd: '''nim c --gc:arc --threads:on $file'''
disabled: "bsd"
matrix: "--gc:arc --threads:on"
"""

# bug #13936
Expand Down
2 changes: 1 addition & 1 deletion tests/cpp/temitlist.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ disabled: "windows" # pending bug #18011

# bug #4730

type Vector* {.importcpp: "std::vector", header: "<vector>".}[T] = object
type Vector*[T] {.importcpp: "std::vector", header: "<vector>".} = object

template `[]=`*[T](v: var Vector[T], key: int, val: T) =
{.emit: [v, "[", key, "] = ", val, ";"].}
Expand Down
4 changes: 2 additions & 2 deletions tests/cpp/tvector_iterator.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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]

2 changes: 1 addition & 1 deletion tests/errmsgs/tinvalidinout.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/exception/tcpp_imported_exc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ doAssert(getCurrentException() == nil)
# raise by pointer and also generic type

type
std_vector {.importcpp"std::vector", header"<vector>".} [T] = object
std_vector[T] {.importcpp"std::vector", header"<vector>".} = 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;".}
Expand Down
4 changes: 2 additions & 2 deletions tests/generics/tgeneric3.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ 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]
when not (D is string):
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
Expand Down
2 changes: 1 addition & 1 deletion tests/iter/titer2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 3 additions & 3 deletions tests/misc/tsimplesort.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion tests/misc/tsizeof.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions tests/statictypes/tstaticimportcpp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ struct SimpleStruct {
""" .}

type
GenericIntType {.importcpp: "GenericIntType<'0, '1>".} [N: static[int]; T] = object
GenericIntType[N: static[int]; T] {.importcpp: "GenericIntType<'0, '1>".} = object
data: array[N, T]

GenericIntTypeAlt {.importcpp: "GenericIntType".} [N: static[int]; T] = object
GenericIntTypeAlt[N: static[int]; T] {.importcpp: "GenericIntType".} = object

GenericTType {.importcpp: "GenericTType<'0>".} [T] = object
GenericTType[T] {.importcpp: "GenericTType<'0>".} = object
field: T

GenInt4 = GenericIntType[4, int]
Expand Down

0 comments on commit 983a875

Please sign in to comment.