This module implements the instantiation of generic procs. included from sem.nimThis module implements semantic checking for calls. included from sem.nimthis module does the semantic checking of type declarations included from sem.nimThe current implementation of templates might not yet conform to the description that follows.
Template Basics
Given a basic template as follows: ..code:
template identity(arg: untyped): untyped = arg
The template's output type is untyped, meaning the body (arg) is treated as an untyped AST fragment, that substitution of parameters will evaluate per the rules of untyped templates, and finally evaluation and insertion of the template at the callsite will be hygeinic. The template parameter arg will be captured as untyped, meaning no attempt will be made to semantically analyse the parameter prior to substitution.
Template Taxonomy
There are at least four types of templates across two categories:
- AST templates:
- untyped
- dirty a non-hygienic sub-variant
- typed
- untyped
- expression templates (all types that are not untyped or typed)
Substitution Positions
Templates are ultimately AST level constructs regardless of output type, they must be valid syntax. There are two types of positions in a template body, one is definition and the other is usage. A definition is any position where the grammar construct is intended to introduce a new symbol, i.e.: the name of a routine, including its parameters; names of variables (const, let, var), and so on. All other sites are usage sites, where a symbol referring to a "chunk" of AST might be used.
This is a draft of subsitution rules:
- untyped template bodies accept untyped params in definition or usage positions; and all other params are usage only
- typed template bodies accept untyped params in definition or usage positions; and all other params are usage only
- non-ast template bodies only allow subsitutions within usage positions
This implements the first pass over the generic body; it resolves some symbols. Thus for generics there is a two-phase symbol lookup.
A two-phase lookup as today is templates and not generics, AKA mistake.
A problem is that it cannot be detected if the symbol is introduced as in var x = ... or used because macros/templates can hide this! So we have to eval templates/macros right here so that symbol lookup can be accurate.
included from sem.nim- this module does the semantic checking of statements
- included from sem.nim
- This module does the semantic transformation of the fields* iterators.
- included from semstmts.nim
Future Considerations/Improvements:
- The return nil pattern leads to a lot of boilerplate, most of this is for PNodes which can be converted to use nkEmpty and/or optional.
Imports
-
../ast/ast, ../ast/astalgo, ../ast/checked_ast, ../ast/trees, ../ast/wordrecg, ../ast/renderer, ../ast/types, ../ast/nimsets, ../ast/errorreporting, ../ast/errorhandling, ../ast/astmsgs, ../ast/lineinfos, ../ast/idents, ../ast/enumtostr, ../ast/linter, ../modules/magicsys, ../modules/modulepaths, ../modules/importer, ../modules/modulegraphs, ../front/options, ../front/msgs, ../utils/ropes, ../utils/platform, ../utils/nversion, ../utils/debugutils, ../utils/int128, ../utils/astrepr, ../utils/idioms, semfold, typeallowed, isolation_check, procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, transf, aliases, sempass2, patterns, parampatterns, evaltempl, lowerings, ../backend/cgmeth, ../plugins/active, ../vm/compilerbridge, ../vm/vmdef, ../ast/reports_sem, ../ast/reports_vm, ../ast/report_enums, ../tools/suggest, ../ast/typesrenderer, ../front/optionsprocessor
Consts
tyGenericLike = {tyGenericInvocation, tyGenericInst, tyArray, tySet, tySequence, tyOpenArray, tyUserTypeClassInst..tyCompositeTypeClass}
- Source Edit
tyMagicGenerics = {tySet, tySequence, tyArray, tyOpenArray}
- Source Edit
tyUserDefinedGenerics = {tyGenericInst, tyGenericInvocation, tyUserTypeClassInst}
- Source Edit
Procs
proc commonType(c: PContext; x, y: PType): PType {. ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
- Source Edit
proc commonType(c: PContext; x: PType; y: PNode): PType {. ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
- Source Edit
func defNameErrorNodeAllowsSymUpdate(n: PNode): bool {.inline, ...raises: [], tags: [].}
- true if n is an nkError of kind adSemSymNameSym and the error is minor enough to allow the recovery sym to be updated. Used to see if progress is allowed inspite of errors. Source Edit
func getDefNameSymOrRecover(n: PNode): PSym {.inline, ...raises: [], tags: [].}
- extracts the symbol from n, which must be an nkSym or nkError with diagnostic kind of adSemDefNameSym. If n is an error, a recovery symbol is extracted, allowing progress to be made. Source Edit
proc instGenericConvertersArg(c: PContext; a: PNode; x: TCandidate) {. ...raises: [Exception, ERecoverableError, KeyError, ValueError], tags: [RootEffect, ReadDirEffect, ReadIOEffect, ReadEnvEffect, TimeEffect].}
- Source Edit
proc instGenericConvertersSons(c: PContext; n: PNode; x: TCandidate) {. ...raises: [Exception, ERecoverableError, KeyError, ValueError], tags: [RootEffect, ReadDirEffect, ReadIOEffect, ReadEnvEffect, TimeEffect].}
- Source Edit
proc maybeResemArgs(c: PContext; n: PNode; startIdx: int = 1): seq[PNode] {. ...raises: [Exception], tags: [RootEffect].}
- Source Edit
proc newSymGNode(kind: TSymKind; n: PNode; c: PContext): PNode {....raises: [], tags: [].}
-
like newSymS, but considers gensym'ed symbols, analyses n producing a canonical symbol node (nkSym), or if unsuccessful an nkError with an adSemDefNameSym diagnostic.
Symbol canonicalization is is as follows:
- nkSym -> match kind (or skTemp) and updates the sym owner to the
- current context (gensym specific)
- nkIdentKinds -> instantiate a symbol considering quoted identifiers
- nkError -> simply returns the same error
- other kinds -> new error
proc toLiterals(vals: IntSet; t: PType): seq[PNode] {....raises: [], tags: [].}
- Source Edit
Templates
template commonTypeBegin(): PType
- Source Edit