Skip to content

Commit

Permalink
Add {.alias.} pragma
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Nov 26, 2022
1 parent b57a963 commit f9fd76d
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 15 deletions.
16 changes: 16 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,22 @@
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
- Alias-style templates and macros can now optionally be annotated with the
`{.alias.}` pragma. For templates, this has the behavior of disallowing
redefinitions.
```nim
type Foo = object
bar: int
var foo = Foo(bar: 10)
template bar: untyped {.alias.} = foo.bar
assert bar == 10
bar = 15
assert bar == 15
var foo2 = Foo(bar: -10)
# error:
template bar: untyped {.alias.} = foo.bar
```

- `cstring` is now accepted as a selector in `case` statements, removing the
Expand Down
1 change: 1 addition & 0 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ const
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
sfGoto* = sfOverriden # var is used for 'goto' code generation
sfAliasStyle* = sfConstructor # alias-style template or macro
sfWrittenTo* = sfBorrow # param is assigned to
# currently unimplemented
sfBase* = sfDiscriminant
Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasTopDownInference")
defineSymbol("nimHasTemplateRedefinitionPragma")
defineSymbol("nimHasCstringCase")
defineSymbol("nimHasAliasPragma")
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")

Expand Down
6 changes: 4 additions & 2 deletions compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ const
converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
wDelegator, wExportNims, wUsed, wPragma, wRedefine, wCallsite}
wDelegator, wExportNims, wUsed, wPragma, wRedefine, wCallsite, wAlias}
macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
wDiscardable, wGensym, wInject, wDelegator}
wDiscardable, wGensym, wInject, wDelegator, wAlias}
iteratorPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect,
wMagic, wBorrow,
wDiscardable, wGensym, wInject, wRaises, wEffectsOf,
Expand Down Expand Up @@ -1231,6 +1231,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
sym.flags.incl sfNeverRaises
of wSystemRaisesDefect:
sym.flags.incl sfSystemRaisesDefect
of wAlias:
sym.flags.incl sfAliasStyle
else: invalidPragma(c, it)
elif comesFromPush and whichKeyword(ident) != wInvalid:
discard "ignore the .push pragma; it doesn't apply"
Expand Down
7 changes: 5 additions & 2 deletions compiler/semtempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -690,8 +690,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
addInterfaceOverloadableSymAt(c, c.currentScope, s)
elif not comesFromShadowscope:
if {sfTemplateRedefinition, sfGenSym} * s.flags == {}:
#wrongRedefinition(c, n.info, proto.name.s, proto.info)
message(c.config, n.info, warnTemplateRedefinition, s.name.s)
if sfAlias in (proto.flags + s.flags):
# cannot implicitly redefine alias templates
wrongRedefinition(c, n.info, proto.name.s, proto.info)
else:
message(c.config, n.info, warnTemplateRedefinition, s.name.s)
symTabReplace(c.currentScope.symbols, proto, s)
if n[patternPos].kind != nkEmpty:
c.patterns.add(s)
Expand Down
2 changes: 1 addition & 1 deletion compiler/wordrecg.nim
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ type
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", wSystemRaisesDefect = "systemRaisesDefect",
wRedefine = "redefine", wCallsite = "callsite",
wRedefine = "redefine", wCallsite = "callsite", wAlias = "alias",

wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default",
Expand Down
26 changes: 21 additions & 5 deletions doc/manual_experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ Assuming `foo` is a macro or a template, this is roughly equivalent to:
```


Symbols as template/macro calls
===============================
Alias-style templates and macros
================================

Templates and macros that take no arguments can be called as lone symbols,
i.e. without parentheses. This is useful for repeated uses of complex
Expand All @@ -448,9 +448,25 @@ expressions that cannot conveniently be represented as runtime values.
assert bar == 15
```

In the future, this may require more specific information on template or macro
signatures to be used. Specializations for some applications of this may also
be introduced to guarantee consistency and circumvent bugs.
These templates/macros can be annotated with the `{.alias.}` pragma
to denote their intended use, however this annotation is currently
not required. For templates, this induces the behavior of
disallowing redefinitions.

.. code-block:: nim
type Foo = object
bar: int

var foo = Foo(bar: 10)
template bar: untyped {.alias.} = foo.bar
assert bar == 10
bar = 15
assert bar == 15
var foo2 = Foo(bar: -10)
# error:
template bar: untyped {.alias.} = foo.bar

In the future, this annotation or the lack of it may gain more meanings.


Not nil annotation
Expand Down
11 changes: 8 additions & 3 deletions lib/std/decls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ macro byaddr*(sect) =
typ = def[1]
ex = def[2]
addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ)
result = quote do:
let tmp: `addrTyp` = addr(`ex`)
template `lhs`: untyped = tmp[]
when defined(nimHasAliasPragma):
result = quote do:
let tmp: `addrTyp` = addr(`ex`)
template `lhs`: untyped {.alias.} = tmp[]
else:
result = quote do:
let tmp: `addrTyp` = addr(`ex`)
template `lhs`: untyped = tmp[]
result.copyLineInfo(def)
4 changes: 2 additions & 2 deletions tests/stdlib/tdecls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ template fun() =
var b {.byaddr.}: int = s[0]
doAssert a.addr == b.addr

when false:
# template specific redeclaration issue
when defined(nimHasAliasPragma):
# use of {.alias.} pragma disallows redefinitions
# see https://github.com/nim-lang/Nim/issues/8275
doAssert not compiles(block:
# redeclaration not allowed
Expand Down

0 comments on commit f9fd76d

Please sign in to comment.