Merge remote-tracking branch 'origin/concepts-rebased' into araq
This commit is contained in:
commit
529609f7ed
47 changed files with 2038 additions and 345 deletions
|
|
@ -252,6 +252,7 @@ type
|
|||
sfProcvar, # proc can be passed to a proc var
|
||||
sfDiscriminant, # field is a discriminant in a record/object
|
||||
sfDeprecated, # symbol is deprecated
|
||||
sfExplain, # provide more diagnostics when this symbol is used
|
||||
sfError, # usage of symbol should trigger a compile-time error
|
||||
sfShadowed, # a symbol that was shadowed in some inner scope
|
||||
sfThread, # proc will run as a thread
|
||||
|
|
@ -354,44 +355,52 @@ type
|
|||
tyUnused,
|
||||
tyProxy # used as errornous type (for idetools)
|
||||
|
||||
tyBuiltInTypeClass #\
|
||||
tyBuiltInTypeClass
|
||||
# Type such as the catch-all object, tuple, seq, etc
|
||||
|
||||
tyUserTypeClass #\
|
||||
tyUserTypeClass
|
||||
# the body of a user-defined type class
|
||||
|
||||
tyUserTypeClassInst #\
|
||||
tyUserTypeClassInst
|
||||
# Instance of a parametric user-defined type class.
|
||||
# Structured similarly to tyGenericInst.
|
||||
# tyGenericInst represents concrete types, while
|
||||
# this is still a "generic param" that will bind types
|
||||
# and resolves them during sigmatch and instantiation.
|
||||
|
||||
tyCompositeTypeClass #\
|
||||
tyCompositeTypeClass
|
||||
# Type such as seq[Number]
|
||||
# The notes for tyUserTypeClassInst apply here as well
|
||||
# sons[0]: the original expression used by the user.
|
||||
# sons[1]: fully expanded and instantiated meta type
|
||||
# (potentially following aliases)
|
||||
|
||||
tyAnd, tyOr, tyNot #\
|
||||
tyInferred
|
||||
# In the initial state `base` stores a type class constraining
|
||||
# the types that can be inferred. After a candidate type is
|
||||
# selected, it's stored in `lastSon`. Between `base` and `lastSon`
|
||||
# there may be 0, 2 or more types that were also considered as
|
||||
# possible candidates in the inference process (i.e. lastSon will
|
||||
# be updated to store a type best conforming to all candidates)
|
||||
|
||||
tyAnd, tyOr, tyNot
|
||||
# boolean type classes such as `string|int`,`not seq`,
|
||||
# `Sortable and Enumable`, etc
|
||||
|
||||
tyAnything #\
|
||||
tyAnything
|
||||
# a type class matching any type
|
||||
|
||||
tyStatic #\
|
||||
tyStatic
|
||||
# a value known at compile type (the underlying type is .base)
|
||||
|
||||
tyFromExpr #\
|
||||
tyFromExpr
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the expression is stored in t.n)
|
||||
# It will be converted to a real type only during generic
|
||||
# instantiation and prior to this it has the potential to
|
||||
# be any type.
|
||||
|
||||
tyFieldAccessor #\
|
||||
tyFieldAccessor
|
||||
# Expressions such as Type.field (valid in contexts such
|
||||
# as the `is` operator and magics like `high` and `low`).
|
||||
# Could be lifted to a single argument proc returning the
|
||||
|
|
@ -400,7 +409,7 @@ type
|
|||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
tyVoid #\
|
||||
tyVoid
|
||||
# now different from tyEmpty, hurray!
|
||||
|
||||
static:
|
||||
|
|
@ -420,6 +429,7 @@ const
|
|||
tyAnd, tyOr, tyNot, tyAnything}
|
||||
|
||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
|
||||
tyUserTypeClasses* = {tyUserTypeClass, tyUserTypeClassInst}
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
|
@ -463,6 +473,8 @@ type
|
|||
# can be attached to generic procs with free standing
|
||||
# type parameters: e.g. proc foo[T]()
|
||||
# depends on unresolved static params.
|
||||
tfResolved # marks a user type class, after it has been bound to a
|
||||
# concrete type (lastSon becomes the concrete type)
|
||||
tfRetType, # marks return types in proc (used to detect type classes
|
||||
# used as return types for return type inference)
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
|
|
@ -482,6 +494,9 @@ type
|
|||
tfHasStatic
|
||||
tfGenericTypeParam
|
||||
tfImplicitTypeParam
|
||||
tfInferrableStatic
|
||||
tfExplicit # for typedescs, marks types explicitly prefixed with the
|
||||
# `type` operator (e.g. type int)
|
||||
tfWildcard # consider a proc like foo[T, I](x: Type[T, I])
|
||||
# T and I here can bind to both typedesc and static types
|
||||
# before this is determined, we'll consider them to be a
|
||||
|
|
@ -1036,6 +1051,9 @@ proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
|||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
template previouslyInferred*(t: PType): PType =
|
||||
if t.sons.len > 1: t.lastSon else: nil
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
|
|
@ -1062,6 +1080,9 @@ proc isMetaType*(t: PType): bool =
|
|||
(t.kind == tyStatic and t.n == nil) or
|
||||
tfHasMeta in t.flags
|
||||
|
||||
proc isUnresolvedStatic*(t: PType): bool =
|
||||
return t.kind == tyStatic and t.n == nil
|
||||
|
||||
proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
|
||||
t.sym = s
|
||||
s.typ = t
|
||||
|
|
@ -1278,6 +1299,8 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
|||
when debugIds: registerId(result)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc exactReplica*(t: PType): PType = copyType(t, t.owner, true)
|
||||
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
|
|
@ -1561,7 +1584,7 @@ proc hasPattern*(s: PSym): bool {.inline.} =
|
|||
result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
|
||||
|
||||
iterator items*(n: PNode): PNode =
|
||||
for i in 0.. <n.len: yield n.sons[i]
|
||||
for i in 0.. <n.safeLen: yield n.sons[i]
|
||||
|
||||
iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
|
||||
for i in 0.. <n.len: yield (i, n.sons[i])
|
||||
|
|
@ -1604,6 +1627,16 @@ proc toObject*(typ: PType): PType =
|
|||
if result.kind == tyRef:
|
||||
result = result.lastSon
|
||||
|
||||
proc findUnresolvedStatic*(n: PNode): PNode =
|
||||
if n.kind == nkSym and n.typ.kind == tyStatic and n.typ.n == nil:
|
||||
return n
|
||||
|
||||
for son in n:
|
||||
let n = son.findUnresolvedStatic
|
||||
if n != nil: return n
|
||||
|
||||
return nil
|
||||
|
||||
when false:
|
||||
proc containsNil*(n: PNode): bool =
|
||||
# only for debugging
|
||||
|
|
|
|||
|
|
@ -890,7 +890,7 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
|||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
|
||||
|
||||
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
|
||||
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
||||
case ty.kind
|
||||
of tyArray: genArrayElem(p, n.sons[0], n.sons[1], d)
|
||||
|
|
@ -1359,7 +1359,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
|||
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
var a = e.sons[1]
|
||||
if a.kind == nkHiddenAddr: a = a.sons[0]
|
||||
let typ = skipTypes(a.typ, abstractVar)
|
||||
var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
|
||||
case typ.kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
|
||||
|
|
|
|||
|
|
@ -164,8 +164,11 @@ proc mapType(typ: PType): TCTypeKind =
|
|||
of tySet: result = mapSetType(typ)
|
||||
of tyOpenArray, tyArray, tyVarargs: result = ctArray
|
||||
of tyObject, tyTuple: result = ctStruct
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
internalAssert typ.isResolvedUserTypeClass
|
||||
return mapType(typ.lastSon)
|
||||
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias:
|
||||
tyTypeDesc, tyAlias, tyInferred:
|
||||
result = mapType(lastSon(typ))
|
||||
of tyEnum:
|
||||
if firstOrd(typ) < 0:
|
||||
|
|
@ -787,7 +790,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
|||
of 1, 2, 4, 8: addf(m.s[cfsTypes], "typedef NU$2 $1;$n", [result, rope(s*8)])
|
||||
else: addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
|
||||
[result, rope(getSize(t))])
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias:
|
||||
of tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
|
||||
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
|
||||
result = getTypeDescAux(m, lastSon(t), check)
|
||||
else:
|
||||
internalError("getTypeDescAux(" & $t.kind & ')')
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ proc getUniqueType*(key: PType): PType =
|
|||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||
if key.isResolvedUserTypeClass:
|
||||
return getUniqueType(lastSon(key))
|
||||
if key.sym != nil:
|
||||
internalError(key.sym.info, "metatype not eliminated")
|
||||
else:
|
||||
|
|
@ -108,7 +110,7 @@ proc getUniqueType*(key: PType): PType =
|
|||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
of tyGenericInst, tyOrdinal, tyStatic, tyAlias:
|
||||
of tyGenericInst, tyOrdinal, tyStatic, tyAlias, tyInferred:
|
||||
result = getUniqueType(lastSon(key))
|
||||
#let obj = lastSon(key)
|
||||
#if obj.sym != nil and obj.sym.name.s == "TOption":
|
||||
|
|
|
|||
|
|
@ -478,8 +478,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
|||
of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
|
||||
of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
|
||||
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||
of "reportconceptfailures":
|
||||
processOnOffSwitchG({optReportConceptFailures}, arg, pass, info)
|
||||
of "threads":
|
||||
processOnOffSwitchG({optThreads}, arg, pass, info)
|
||||
#if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ proc mapType(typ: PType): TJSTypeKind =
|
|||
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||
tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid, tyAlias:
|
||||
result = etyNone
|
||||
of tyInferred:
|
||||
result = mapType(typ.lastSon)
|
||||
of tyStatic:
|
||||
if t.n != nil: result = mapType(lastSon t)
|
||||
else: result = etyNone
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ type
|
|||
errXCannotBeClosure, errXMustBeCompileTime,
|
||||
errCannotInferTypeOfTheLiteral,
|
||||
errCannotInferReturnType,
|
||||
errCannotInferStaticParam,
|
||||
errGenericLambdaNotAllowed,
|
||||
errProcHasNoConcreteType,
|
||||
errCompilerDoesntSupportTarget,
|
||||
|
|
@ -132,7 +133,7 @@ type
|
|||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintExecuting, hintLinking, hintDependency,
|
||||
hintSource, hintStackTrace, hintGCStats,
|
||||
hintUser
|
||||
hintUser, hintUserRaw
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
|
|
@ -373,6 +374,7 @@ const
|
|||
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
|
||||
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
|
||||
errCannotInferReturnType: "cannot infer the return type of the proc",
|
||||
errCannotInferStaticParam: "cannot infer the value of the static param `$1`",
|
||||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be inferred from the expected signature.",
|
||||
|
|
@ -432,10 +434,11 @@ const
|
|||
hintSource: "$1",
|
||||
hintStackTrace: "$1",
|
||||
hintGCStats: "$1",
|
||||
hintUser: "$1"]
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
|
|
@ -447,12 +450,12 @@ const
|
|||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||
|
||||
HintsToStr*: array[0..22, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "StackTrace", "GCStats",
|
||||
"User"]
|
||||
"User", "UserRaw"]
|
||||
|
||||
const
|
||||
fatalMin* = errUnknown
|
||||
|
|
@ -497,7 +500,6 @@ type
|
|||
TErrorOutput* = enum
|
||||
eStdOut
|
||||
eStdErr
|
||||
eInMemory
|
||||
|
||||
TErrorOutputs* = set[TErrorOutput]
|
||||
|
||||
|
|
@ -651,6 +653,12 @@ var
|
|||
writelnHook*: proc (output: string) {.closure.}
|
||||
structuredErrorHook*: proc (info: TLineInfo; msg: string; severity: Severity) {.closure.}
|
||||
|
||||
proc concat(strings: openarray[string]): string =
|
||||
var totalLen = 0
|
||||
for s in strings: totalLen += s.len
|
||||
result = newStringOfCap totalLen
|
||||
for s in strings: result.add s
|
||||
|
||||
proc suggestWriteln*(s: string) =
|
||||
if eStdOut in errorOutputs:
|
||||
if isNil(writelnHook):
|
||||
|
|
@ -804,10 +812,7 @@ macro callStyledWriteLineStderr(args: varargs[typed]): untyped =
|
|||
result.add(arg)
|
||||
|
||||
template callWritelnHook(args: varargs[string, `$`]) =
|
||||
var s = ""
|
||||
for arg in args:
|
||||
s.add arg
|
||||
writelnHook s
|
||||
writelnHook concat(args)
|
||||
|
||||
template styledMsgWriteln*(args: varargs[typed]) =
|
||||
if not isNil(writelnHook):
|
||||
|
|
@ -922,7 +927,7 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
|||
if msg notin gNotes: return
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
let s = msgKindToString(msg) % args
|
||||
|
||||
|
|
@ -990,7 +995,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
|||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
# NOTE: currently line info line numbers start with 1,
|
||||
# but column numbers start with 0, however most editors expect
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ type # please make sure we have under 32 options
|
|||
TGlobalOption* = enum # **keep binary compatible**
|
||||
gloptNone, optForceFullMake, optDeadCodeElim,
|
||||
optListCmd, optCompileOnly, optNoLinking,
|
||||
optReportConceptFailures, # report 'compiles' or 'concept' matching failures
|
||||
optCDebug, # turn on debugging information
|
||||
optGenDynLib, # generate a dynamic library
|
||||
optGenStaticLib, # generate a static library
|
||||
|
|
@ -73,8 +72,8 @@ type # please make sure we have under 32 options
|
|||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
const
|
||||
harmlessOptions* = {optForceFullMake, optNoLinking, optReportConceptFailures,
|
||||
optRun, optUseColors, optStdout}
|
||||
harmlessOptions* = {optForceFullMake, optNoLinking, optRun,
|
||||
optUseColors, optStdout}
|
||||
|
||||
type
|
||||
TCommands* = enum # Nim's commands
|
||||
|
|
|
|||
|
|
@ -235,6 +235,13 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
|||
of nkStmtList, nkStmtListExpr:
|
||||
if n.typ != nil:
|
||||
result = isAssignable(owner, n.lastSon, isUnsafeAddr)
|
||||
of nkVarTy:
|
||||
# XXX: The fact that this is here is a bit of a hack.
|
||||
# The goal is to allow the use of checks such as "foo(var T)"
|
||||
# within concepts. Semantically, it's not correct to say that
|
||||
# nkVarTy denotes an lvalue, but the example above is the only
|
||||
# possible code which will get us here
|
||||
result = arLValue
|
||||
else:
|
||||
discard
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ proc parseSymbol*(p: var TParser, allowNil = false): PNode
|
|||
proc parseTry(p: var TParser; isExpr: bool): PNode
|
||||
proc parseCase(p: var TParser): PNode
|
||||
proc parseStmtPragma(p: var TParser): PNode
|
||||
proc parsePragma(p: var TParser): PNode
|
||||
# implementation
|
||||
|
||||
proc getTok(p: var TParser) =
|
||||
|
|
@ -770,6 +771,13 @@ proc parseOperators(p: var TParser, headNode: PNode,
|
|||
|
||||
proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
|
||||
result = primary(p, mode)
|
||||
if p.tok.tokType == tkCurlyDotLe and
|
||||
p.lex.lineNumber == result.info.line and
|
||||
mode == pmNormal:
|
||||
var pragmaExp = newNodeP(nkPragmaExpr, p)
|
||||
pragmaExp.addSon result
|
||||
pragmaExp.addSon p.parsePragma
|
||||
result = pragmaExp
|
||||
result = parseOperators(p, result, limit, mode)
|
||||
|
||||
proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
|
||||
|
|
@ -1793,8 +1801,16 @@ proc parseObject(p: var TParser): PNode =
|
|||
addSon(result, parseObjectPart(p))
|
||||
|
||||
proc parseTypeClassParam(p: var TParser): PNode =
|
||||
if p.tok.tokType in {tkOut, tkVar}:
|
||||
result = newNodeP(nkVarTy, p)
|
||||
let modifier = case p.tok.tokType
|
||||
of tkOut, tkVar: nkVarTy
|
||||
of tkPtr: nkPtrTy
|
||||
of tkRef: nkRefTy
|
||||
of tkStatic: nkStaticTy
|
||||
of tkType: nkTypeOfExpr
|
||||
else: nkEmpty
|
||||
|
||||
if modifier != nkEmpty:
|
||||
result = newNodeP(modifier, p)
|
||||
getTok(p)
|
||||
result.addSon(p.parseSymbol)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const
|
|||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||
wBorrow, wGcSafe, wExportNims, wPartial, wUsed}
|
||||
wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||
wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
|
|
@ -73,7 +73,7 @@ const
|
|||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||
# implementation
|
||||
|
||||
proc invalidPragma(n: PNode) =
|
||||
proc invalidPragma*(n: PNode) =
|
||||
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||
|
|
@ -773,6 +773,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
|||
of wProcVar:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfProcvar)
|
||||
of wExplain:
|
||||
sym.flags.incl sfExplain
|
||||
of wDeprecated:
|
||||
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ type
|
|||
pendingWhitespace: int
|
||||
comStack*: seq[PNode] # comment stack
|
||||
flags*: TRenderFlags
|
||||
inGenericParams: bool
|
||||
checkAnon: bool # we're in a context that can contain sfAnon
|
||||
inPragma: int
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
|||
g.flags = renderFlags
|
||||
g.pendingNL = -1
|
||||
g.pendingWhitespace = -1
|
||||
g.checkAnon = false
|
||||
g.inGenericParams = false
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
var length = len(g.tokens)
|
||||
|
|
@ -692,14 +693,14 @@ proc gproc(g: var TSrcGen, n: PNode) =
|
|||
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
gpattern(g, n.sons[patternPos])
|
||||
let oldCheckAnon = g.checkAnon
|
||||
g.checkAnon = true
|
||||
let oldInGenericParams = g.inGenericParams
|
||||
g.inGenericParams = true
|
||||
if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and
|
||||
n[miscPos][1].kind != nkEmpty:
|
||||
gsub(g, n[miscPos][1])
|
||||
else:
|
||||
gsub(g, n.sons[genericParamsPos])
|
||||
g.checkAnon = oldCheckAnon
|
||||
g.inGenericParams = oldInGenericParams
|
||||
gsub(g, n.sons[paramsPos])
|
||||
gsub(g, n.sons[pragmasPos])
|
||||
if renderNoBody notin g.flags:
|
||||
|
|
@ -765,7 +766,10 @@ proc gasm(g: var TSrcGen, n: PNode) =
|
|||
gsub(g, n.sons[1])
|
||||
|
||||
proc gident(g: var TSrcGen, n: PNode) =
|
||||
if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
|
||||
if g.inGenericParams and n.kind == nkSym:
|
||||
if sfAnon in n.sym.flags or
|
||||
(n.typ != nil and tfImplicitTypeParam in n.typ.flags): return
|
||||
|
||||
var t: TTokType
|
||||
var s = atom(n)
|
||||
if (s[0] in lexer.SymChars):
|
||||
|
|
@ -1315,9 +1319,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
gcoms(g)
|
||||
gstmts(g, lastSon(n), c)
|
||||
of nkGenericParams:
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
proc hasExplicitParams(gp: PNode): bool =
|
||||
for p in gp:
|
||||
if p.typ == nil or tfImplicitTypeParam notin p.typ.flags:
|
||||
return true
|
||||
return false
|
||||
|
||||
if n.hasExplicitParams:
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkFormalParams:
|
||||
put(g, tkParLe, "(")
|
||||
gsemicolon(g, n, 1)
|
||||
|
|
|
|||
|
|
@ -215,7 +215,6 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
|||
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
|
||||
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
|
||||
proc isOpImpl(c: PContext, n: PNode): PNode
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags = {}): PNode
|
||||
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
|||
tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
|
||||
tyTypeDesc, tyGenericInvocation, tyForward:
|
||||
internalError(c.info, "assignment requested for type: " & typeToString(t))
|
||||
of tyOrdinal, tyRange,
|
||||
of tyOrdinal, tyRange, tyInferred,
|
||||
tyGenericInst, tyFieldAccessor, tyStatic, tyVar, tyAlias:
|
||||
liftBodyAux(c, lastSon(t), body, x, y)
|
||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("liftBodyAux")
|
||||
|
|
|
|||
|
|
@ -35,10 +35,11 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
|||
proc determineType(c: PContext, s: PSym)
|
||||
|
||||
proc initCandidateSymbols(c: PContext, headSymbol: PNode,
|
||||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
o: var TOverloadIter): seq[tuple[s: PSym, scope: int]] =
|
||||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
o: var TOverloadIter,
|
||||
diagnostics: bool): seq[tuple[s: PSym, scope: int]] =
|
||||
result = @[]
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
|
|
@ -46,8 +47,10 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
|
|||
result.add((symx, o.lastOverloadScope))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if result.len > 0:
|
||||
initCandidate(c, best, result[0].s, initialBinding, result[0].scope)
|
||||
initCandidate(c, alt, result[0].s, initialBinding, result[0].scope)
|
||||
initCandidate(c, best, result[0].s, initialBinding,
|
||||
result[0].scope, diagnostics)
|
||||
initCandidate(c, alt, result[0].s, initialBinding,
|
||||
result[0].scope, diagnostics)
|
||||
best.state = csNoMatch
|
||||
|
||||
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
|
|
@ -55,7 +58,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
initialBinding: PNode,
|
||||
filter: TSymKinds,
|
||||
best, alt: var TCandidate,
|
||||
errors: var CandidateErrors) =
|
||||
errors: var CandidateErrors,
|
||||
diagnosticsFlag = false) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var scope = o.lastOverloadScope
|
||||
|
|
@ -68,8 +72,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
while sym != nil:
|
||||
if sym.kind in filter:
|
||||
# Initialise 'best' and 'alt' with the first available symbol
|
||||
initCandidate(c, best, sym, initialBinding, scope)
|
||||
initCandidate(c, alt, sym, initialBinding, scope)
|
||||
initCandidate(c, best, sym, initialBinding, scope, diagnosticsFlag)
|
||||
initCandidate(c, alt, sym, initialBinding, scope, diagnosticsFlag)
|
||||
best.state = csNoMatch
|
||||
break
|
||||
else:
|
||||
|
|
@ -82,14 +86,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
scope = o.lastOverloadScope
|
||||
continue
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, scope)
|
||||
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
|
||||
if c.currentScope.symbols.counter == counterInitial or syms != nil:
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd((sym, int z.mutabilityProblem))
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
||||
|
|
@ -99,10 +98,16 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
var cmp = cmpCandidates(best, z)
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
elif errors != nil or z.diagnostics != nil:
|
||||
errors.safeAdd(CandidateError(
|
||||
sym: sym,
|
||||
unmatchedVarParam: int z.mutabilityProblem,
|
||||
diagnostics: z.diagnostics))
|
||||
else:
|
||||
# Symbol table has been modified. Restart and pre-calculate all syms
|
||||
# before any further candidate init and compare. SLOW, but rare case.
|
||||
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter, best, alt, o)
|
||||
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
|
||||
best, alt, o, diagnosticsFlag)
|
||||
if syms == nil:
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
scope = o.lastOverloadScope
|
||||
|
|
@ -114,17 +119,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
else:
|
||||
break
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if c.compilesContextId > 0 and optReportConceptFailures notin gGlobalOptions:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.isNil or errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
return
|
||||
|
||||
proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
|
||||
(TPreferedDesc, string) =
|
||||
var prefer = preferName
|
||||
# to avoid confusing errors like:
|
||||
# got (SslPtr, SocketHandle)
|
||||
# but expected one of:
|
||||
|
|
@ -132,11 +129,9 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
|||
# we do a pre-analysis. If all types produce the same string, we will add
|
||||
# module information.
|
||||
let proto = describeArgs(c, n, 1, preferName)
|
||||
|
||||
var prefer = preferName
|
||||
for err, mut in items(errors):
|
||||
for err in errors:
|
||||
var errProto = ""
|
||||
let n = err.typ.n
|
||||
let n = err.sym.typ.n
|
||||
for i in countup(1, n.len - 1):
|
||||
var p = n.sons[i]
|
||||
if p.kind == nkSym:
|
||||
|
|
@ -147,26 +142,40 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
|||
prefer = preferModuleInfo
|
||||
break
|
||||
|
||||
# now use the information stored in 'prefer' to produce a nice error message:
|
||||
var candidates = ""
|
||||
for err in errors:
|
||||
if err.sym.kind in routineKinds and err.sym.ast != nil:
|
||||
add(candidates, renderTree(err.sym.ast,
|
||||
{renderNoBody, renderNoComments, renderNoPragmas}))
|
||||
else:
|
||||
add(candidates, err.sym.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
if err.unmatchedVarParam != 0 and err.unmatchedVarParam < n.len:
|
||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" &
|
||||
renderTree(n[err.unmatchedVarParam]) & "' is immutable\n")
|
||||
for diag in err.diagnostics:
|
||||
add(candidates, diag & "\n")
|
||||
|
||||
result = (prefer, candidates)
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
# as semOverlodedCall is already pretty slow (and we need this information
|
||||
# only in case of an error).
|
||||
if errorOutputs == {}:
|
||||
# fail fast:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
if errors.isNil or errors.len == 0:
|
||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||
return
|
||||
|
||||
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
|
||||
var result = msgKindToString(errTypeMismatch)
|
||||
add(result, describeArgs(c, n, 1, prefer))
|
||||
add(result, ')')
|
||||
var candidates = ""
|
||||
for err, mut in items(errors):
|
||||
if err.kind in routineKinds and err.ast != nil:
|
||||
add(candidates, renderTree(err.ast,
|
||||
{renderNoBody, renderNoComments,renderNoPragmas}))
|
||||
else:
|
||||
add(candidates, err.getProcHeader(prefer))
|
||||
add(candidates, "\n")
|
||||
if mut != 0 and mut < n.len:
|
||||
add(candidates, "for a 'var' type a variable needs to be passed, but '" & renderTree(n[mut]) & "' is immutable\n")
|
||||
if candidates != "":
|
||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||
if c.compilesContextId > 0 and optReportConceptFailures in gGlobalOptions:
|
||||
globalError(n.info, errGenerated, result)
|
||||
else:
|
||||
localError(n.info, errGenerated, result)
|
||||
localError(n.info, errGenerated, result)
|
||||
|
||||
proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||
var errors: CandidateErrors = @[]
|
||||
|
|
@ -175,7 +184,9 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
|||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
while symx != nil:
|
||||
if symx.kind in routineKinds:
|
||||
errors.add((symx, 0))
|
||||
errors.add(CandidateError(sym: symx,
|
||||
unmatchedVarParam: 0,
|
||||
diagnostics: nil))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if errors.len == 0:
|
||||
localError(n.info, "could not resolve: " & $n)
|
||||
|
|
@ -183,7 +194,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
|||
notFoundError(c, n, errors)
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds;
|
||||
filter: TSymKinds, flags: TExprFlags,
|
||||
errors: var CandidateErrors): TCandidate =
|
||||
var initialBinding: PNode
|
||||
var alt: TCandidate
|
||||
|
|
@ -197,7 +208,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
|
||||
template pickBest(headSymbol) =
|
||||
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
|
||||
filter, result, alt, errors)
|
||||
filter, result, alt, errors, efExplain in flags)
|
||||
pickBest(f)
|
||||
|
||||
let overloadsState = result.state
|
||||
|
|
@ -263,18 +274,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
# clean up the inserted ops
|
||||
n.sons.delete(2)
|
||||
n.sons[0] = f
|
||||
|
||||
errors = @[]
|
||||
pickBest(f)
|
||||
#notFoundError(c, n, errors)
|
||||
|
||||
return
|
||||
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
|
||||
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
|
||||
internalAssert result.state == csMatch
|
||||
#writeMatches(result)
|
||||
#writeMatches(alt)
|
||||
if c.compilesContextId > 0:
|
||||
if errorOutputs == {}:
|
||||
# quick error message for performance of 'compiles' built-in:
|
||||
globalError(n.info, errGenerated, "ambiguous call")
|
||||
elif gErrorCounter == 0:
|
||||
|
|
@ -289,7 +295,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
|
||||
args])
|
||||
|
||||
|
||||
proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
|
||||
if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
|
||||
let s = a.sons[0].sym
|
||||
|
|
@ -378,23 +383,40 @@ proc tryDeref(n: PNode): PNode =
|
|||
result.addSon(n)
|
||||
|
||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode =
|
||||
var errors: CandidateErrors
|
||||
|
||||
var r = resolveOverloads(c, n, nOrig, filter, errors)
|
||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||
filter: TSymKinds, flags: TExprFlags): PNode =
|
||||
var errors: CandidateErrors = if efExplain in flags: @[]
|
||||
else: nil
|
||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors)
|
||||
if r.state == csMatch:
|
||||
# this may be triggered, when the explain pragma is used
|
||||
if errors.len > 0:
|
||||
let (_, candidates) = presentFailedCandidates(c, n, errors)
|
||||
message(n.info, hintUserRaw,
|
||||
"Non-matching candidates for " & renderTree(n) & "\n" &
|
||||
candidates)
|
||||
result = semResolvedCall(c, n, r)
|
||||
elif experimentalMode(c) and canDeref(n):
|
||||
# try to deref the first argument and then try overloading resolution again:
|
||||
#
|
||||
# XXX: why is this here?
|
||||
# it could be added to the long list of alternatives tried
|
||||
# inside `resolveOverloads` or it could be moved all the way
|
||||
# into sigmatch with hidden conversion produced there
|
||||
#
|
||||
n.sons[1] = n.sons[1].tryDeref
|
||||
var r = resolveOverloads(c, n, nOrig, filter, errors)
|
||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors)
|
||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||
else:
|
||||
# get rid of the deref again for a better error message:
|
||||
n.sons[1] = n.sons[1].sons[0]
|
||||
notFoundError(c, n, errors)
|
||||
else:
|
||||
notFoundError(c, n, errors)
|
||||
# else: result = errorNode(c, n)
|
||||
if efExplain notin flags:
|
||||
# repeat the overload resolution,
|
||||
# this time enabling all the diagnostic output (this should fail again)
|
||||
discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain})
|
||||
else:
|
||||
notFoundError(c, n, errors)
|
||||
|
||||
proc explicitGenericInstError(n: PNode): PNode =
|
||||
localError(n.info, errCannotInstantiateX, renderTree(n))
|
||||
|
|
@ -450,6 +472,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
|||
if result.len == 1 and a.kind == nkClosedSymChoice:
|
||||
result = result[0]
|
||||
elif result.len == 0: result = explicitGenericInstError(n)
|
||||
# candidateCount != 1: return explicitGenericInstError(n)
|
||||
else:
|
||||
result = explicitGenericInstError(n)
|
||||
|
||||
|
|
@ -473,7 +496,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
|||
x = t.baseOfDistinct
|
||||
call.add(newNodeIT(nkEmpty, fn.info, x))
|
||||
if hasDistinct:
|
||||
var resolved = semOverloadedCall(c, call, call, {fn.kind})
|
||||
var resolved = semOverloadedCall(c, call, call, {fn.kind}, {})
|
||||
if resolved != nil:
|
||||
result = resolved.sons[0].sym
|
||||
if not compareTypes(result.typ.sons[0], fn.typ.sons[0], dcEqIgnoreDistinct):
|
||||
|
|
@ -481,4 +504,3 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
|||
elif result.magic in {mArrPut, mArrGet}:
|
||||
# cannot borrow these magics for now
|
||||
result = nil
|
||||
|
||||
|
|
|
|||
|
|
@ -46,9 +46,10 @@ type
|
|||
|
||||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof,
|
||||
efWantStmt, efAllowStmt, efDetermineType,
|
||||
efWantStmt, efAllowStmt, efDetermineType, efExplain,
|
||||
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
|
||||
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo
|
||||
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo,
|
||||
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
TTypeAttachedOp* = enum
|
||||
|
|
@ -84,12 +85,12 @@ type
|
|||
libs*: seq[PLib] # all libs used by this module
|
||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||
filter: TSymKinds): PNode {.nimcall.}
|
||||
filter: TSymKinds, flags: TExprFlags): PNode {.nimcall.}
|
||||
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
||||
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
|
||||
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
||||
|
|
@ -230,6 +231,17 @@ proc makePtrType*(c: PContext, baseType: PType): PType =
|
|||
result = newTypeS(tyPtr, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeTypeWithModifier*(c: PContext,
|
||||
modifier: TTypeKind,
|
||||
baseType: PType): PType =
|
||||
assert modifier in {tyVar, tyPtr, tyRef, tyStatic, tyTypeDesc}
|
||||
|
||||
if modifier in {tyVar, tyTypeDesc} and baseType.kind == modifier:
|
||||
result = baseType
|
||||
else:
|
||||
result = newTypeS(modifier, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeVarType*(c: PContext, baseType: PType): PType =
|
||||
if baseType.kind == tyVar:
|
||||
result = baseType
|
||||
|
|
@ -238,8 +250,11 @@ proc makeVarType*(c: PContext, baseType: PType): PType =
|
|||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
|
||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
result.addSonSkipIntLit(typ.assertNotNil)
|
||||
if typ.kind == tyTypeDesc:
|
||||
result = typ
|
||||
else:
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
result.addSonSkipIntLit(typ.assertNotNil)
|
||||
|
||||
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||
let typedesc = makeTypeDesc(c, typ)
|
||||
|
|
@ -259,7 +274,8 @@ proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
|||
proc makeStaticExpr*(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStaticExpr, n.info)
|
||||
result.sons = @[n]
|
||||
result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
||||
result.typ = if n.typ != nil and n.typ.kind == tyStatic: n.typ
|
||||
else: newTypeWithSons(c, tyStatic, @[n.typ])
|
||||
|
||||
proc makeAndType*(c: PContext, t1, t2: PType): PType =
|
||||
result = newTypeS(tyAnd, c)
|
||||
|
|
@ -303,16 +319,14 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
|||
let intType = getSysType(tyInt)
|
||||
result = newTypeS(tyRange, c)
|
||||
result.sons = @[intType]
|
||||
if n.typ != nil and n.typ.n == nil:
|
||||
result.flags.incl tfUnresolved
|
||||
result.n = newNode(nkRange, n.info, @[
|
||||
newIntTypeNode(nkIntLit, 0, intType),
|
||||
makeStaticExpr(c, n.nMinusOne)])
|
||||
|
||||
template rangeHasStaticIf*(t: PType): bool =
|
||||
# this accepts the ranges's node
|
||||
t.n != nil and t.n.len > 1 and t.n[1].kind == nkStaticExpr
|
||||
|
||||
template getStaticTypeFromRange*(t: PType): PType =
|
||||
t.n[1][0][1].typ
|
||||
template rangeHasUnresolvedStatic*(t: PType): bool =
|
||||
tfUnresolved in t.flags
|
||||
|
||||
proc errorType*(c: PContext): PType =
|
||||
## creates a type representing an error state
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ proc isCastable(dst, src: PType): bool =
|
|||
# castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
|
||||
# tySequence, tyPointer, tyNil, tyOpenArray,
|
||||
# tyProc, tySet, tyEnum, tyBool, tyChar}
|
||||
let src = src.skipTypes(tyUserTypeClasses)
|
||||
if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
|
||||
return false
|
||||
if skipTypes(src, abstractInst-{tyTypeDesc}).kind == tyTypeDesc:
|
||||
|
|
@ -301,7 +302,7 @@ proc semOf(c: PContext, n: PNode): PNode =
|
|||
n.typ = getSysType(tyBool)
|
||||
result = n
|
||||
|
||||
proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||
proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
internalAssert n.sonsLen == 3 and
|
||||
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
|
||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
|
|
@ -318,16 +319,18 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
|||
else:
|
||||
result = newIntNode(nkIntLit, 0)
|
||||
else:
|
||||
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
||||
var rhsOrigType = n[2].typ
|
||||
var t2 = rhsOrigType.skipTypes({tyTypeDesc})
|
||||
maybeLiftType(t2, c, n.info)
|
||||
var m: TCandidate
|
||||
initCandidate(c, m, t2)
|
||||
if efExplain in flags: m.diagnostics = @[]
|
||||
let match = typeRel(m, t2, t1) >= isSubtype # isNone
|
||||
result = newIntNode(nkIntLit, ord(match))
|
||||
|
||||
result.typ = n.typ
|
||||
|
||||
proc semIs(c: PContext, n: PNode): PNode =
|
||||
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if sonsLen(n) != 3:
|
||||
localError(n.info, errXExpectsTwoArguments, "is")
|
||||
|
||||
|
|
@ -347,7 +350,7 @@ proc semIs(c: PContext, n: PNode): PNode =
|
|||
return
|
||||
|
||||
# BUGFIX: don't evaluate this too early: ``T is void``
|
||||
if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n)
|
||||
if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n, flags)
|
||||
|
||||
proc semOpAux(c: PContext, n: PNode) =
|
||||
const flags = {efDetermineType}
|
||||
|
|
@ -625,6 +628,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
|||
|
||||
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
||||
let a = semExpr(c, n.sons[0])
|
||||
if a.findUnresolvedStatic != nil: return a
|
||||
result = evalStaticExpr(c.module, c.cache, a, c.p.owner)
|
||||
if result.isNil:
|
||||
localError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||
|
|
@ -640,10 +644,10 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
|||
# for typeof support.
|
||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||
result = semOverloadedCall(c, n, nOrig,
|
||||
{skProc, skMethod, skConverter, skMacro, skTemplate, skIterator})
|
||||
{skProc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags)
|
||||
else:
|
||||
result = semOverloadedCall(c, n, nOrig,
|
||||
{skProc, skMethod, skConverter, skMacro, skTemplate})
|
||||
{skProc, skMethod, skConverter, skMacro, skTemplate}, flags)
|
||||
|
||||
if result != nil:
|
||||
if result.sons[0].kind != nkSym:
|
||||
|
|
@ -751,7 +755,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# This is a proc variable, apply normal overload resolution
|
||||
let m = resolveIndirectCall(c, n, nOrig, t)
|
||||
if m.state != csMatch:
|
||||
if c.compilesContextId > 0:
|
||||
if errorOutputs == {}:
|
||||
# speed up error generation:
|
||||
globalError(n.info, errTypeMismatch, "")
|
||||
return emptyNode
|
||||
|
|
@ -912,20 +916,42 @@ const
|
|||
|
||||
proc readTypeParameter(c: PContext, typ: PType,
|
||||
paramName: PIdent, info: TLineInfo): PNode =
|
||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||
else: (internalAssert(typ.kind == tyCompositeTypeClass);
|
||||
typ.sons[1].skipGenericAlias)
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
if tParam.sym.name.id == paramName.id:
|
||||
let rawTyp = ty.sons[s + 1]
|
||||
if rawTyp.kind == tyStatic:
|
||||
return rawTyp.n
|
||||
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst}:
|
||||
for statement in typ.n:
|
||||
case statement.kind
|
||||
of nkTypeSection:
|
||||
for def in statement:
|
||||
if def[0].sym.name.id == paramName.id:
|
||||
# XXX: Instead of lifting the section type to a typedesc
|
||||
# here, we could try doing it earlier in semTypeSection.
|
||||
# This seems semantically correct and then we'll be able
|
||||
# to return the section symbol directly here
|
||||
let foundType = makeTypeDesc(c, def[2].typ)
|
||||
return newSymNode(copySym(def[0].sym).linkTo(foundType), info)
|
||||
|
||||
of nkConstSection:
|
||||
for def in statement:
|
||||
if def[0].sym.name.id == paramName.id:
|
||||
return def[2]
|
||||
|
||||
else:
|
||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||
#echo "came here: returned nil"
|
||||
discard
|
||||
|
||||
if typ.kind != tyUserTypeClass:
|
||||
let ty = if typ.kind == tyCompositeTypeClass: typ.sons[1].skipGenericAlias
|
||||
else: typ.skipGenericAlias
|
||||
let tbody = ty.sons[0]
|
||||
for s in countup(0, tbody.len-2):
|
||||
let tParam = tbody.sons[s]
|
||||
if tParam.sym.name.id == paramName.id:
|
||||
let rawTyp = ty.sons[s + 1]
|
||||
if rawTyp.kind == tyStatic:
|
||||
return rawTyp.n
|
||||
else:
|
||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||
|
||||
return nil
|
||||
|
||||
proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
let s = getGenSym(c, sym)
|
||||
|
|
@ -1080,6 +1106,23 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
var ty = n.sons[0].typ
|
||||
var f: PSym = nil
|
||||
result = nil
|
||||
|
||||
template tryReadingGenericParam(t: PType) =
|
||||
case t.kind
|
||||
of tyTypeParamsHolders:
|
||||
return readTypeParameter(c, t, i, n.info)
|
||||
of tyUserTypeClasses:
|
||||
if t.isResolvedUserTypeClass:
|
||||
return readTypeParameter(c, t, i, n.info)
|
||||
else:
|
||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||
return n
|
||||
of tyGenericParam:
|
||||
n.typ = makeTypeFromExpr(c, copyTree(n))
|
||||
return n
|
||||
else:
|
||||
discard
|
||||
|
||||
if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
|
||||
if ty.kind == tyTypeDesc: ty = ty.base
|
||||
ty = ty.skipTypes(tyDotOpTransparent)
|
||||
|
|
@ -1097,8 +1140,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
markUsed(n.info, f, c.graph.usageSym)
|
||||
styleCheckUse(n.info, f)
|
||||
return
|
||||
of tyTypeParamsHolders:
|
||||
return readTypeParameter(c, ty, i, n.info)
|
||||
of tyObject, tyTuple:
|
||||
if ty.n != nil and ty.n.kind == nkRecList:
|
||||
let field = lookupInRecord(ty.n, i)
|
||||
|
|
@ -1107,8 +1148,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
n.typ.n = copyTree(n)
|
||||
return n
|
||||
else:
|
||||
# echo "TYPE FIELD ACCESS"
|
||||
# debug ty
|
||||
tryReadingGenericParam(ty)
|
||||
return
|
||||
# XXX: This is probably not relevant any more
|
||||
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
|
||||
|
|
@ -1151,8 +1191,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
# we didn't find any field, let's look for a generic param
|
||||
if result == nil:
|
||||
let t = n.sons[0].typ.skipTypes(tyDotOpTransparent)
|
||||
if t.kind in tyTypeParamsHolders:
|
||||
result = readTypeParameter(c, t, i, n.info)
|
||||
tryReadingGenericParam(t)
|
||||
|
||||
proc dotTransformation(c: PContext, n: PNode): PNode =
|
||||
if isSymChoice(n.sons[1]):
|
||||
|
|
@ -1718,7 +1757,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
let oldOwnerLen = len(c.graph.owners)
|
||||
let oldGenerics = c.generics
|
||||
let oldErrorOutputs = errorOutputs
|
||||
errorOutputs = {}
|
||||
if efExplain notin flags: errorOutputs = {}
|
||||
let oldContextLen = msgs.getInfoContextLen()
|
||||
|
||||
let oldInGenericContext = c.inGenericContext
|
||||
|
|
@ -1731,8 +1770,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
result = semExpr(c, n, flags)
|
||||
if msgs.gErrorCounter != oldErrorCount: result = nil
|
||||
except ERecoverableError:
|
||||
if optReportConceptFailures in gGlobalOptions:
|
||||
err = getCurrentExceptionMsg()
|
||||
discard
|
||||
# undo symbol table changes (as far as it's possible):
|
||||
c.compilesContextId = oldCompilesId
|
||||
c.generics = oldGenerics
|
||||
|
|
@ -1746,8 +1784,6 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
errorOutputs = oldErrorOutputs
|
||||
msgs.gErrorCounter = oldErrorCount
|
||||
msgs.gErrorMax = oldErrorMax
|
||||
if optReportConceptFailures in gGlobalOptions and not err.isNil:
|
||||
localError(n.info, err)
|
||||
|
||||
proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# we replace this node by a 'true' or 'false' node:
|
||||
|
|
@ -1814,7 +1850,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
of mLow: result = semLowHigh(c, setMs(n, s), mLow)
|
||||
of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
|
||||
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
||||
of mIs: result = semIs(c, setMs(n, s))
|
||||
of mIs: result = semIs(c, setMs(n, s), flags)
|
||||
of mOf: result = semOf(c, setMs(n, s))
|
||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
||||
|
|
@ -2327,8 +2363,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkCurlyExpr:
|
||||
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
|
||||
of nkPragmaExpr:
|
||||
# which pragmas are allowed for expressions? `likely`, `unlikely`
|
||||
internalError(n.info, "semExpr() to implement") # XXX: to implement
|
||||
var
|
||||
expr = n[0]
|
||||
pragma = n[1]
|
||||
pragmaName = considerQuotedIdent(pragma[0])
|
||||
flags = flags
|
||||
|
||||
case whichKeyword(pragmaName)
|
||||
of wExplain:
|
||||
flags.incl efExplain
|
||||
else:
|
||||
# what other pragmas are allowed for expressions? `likely`, `unlikely`
|
||||
invalidPragma(n)
|
||||
|
||||
result = semExpr(c, n[0], flags)
|
||||
of nkPar:
|
||||
case checkPar(n)
|
||||
of paNone: result = errorNode(c, n)
|
||||
|
|
|
|||
|
|
@ -304,7 +304,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
if isNil(n.sons[bodyPos]):
|
||||
n.sons[bodyPos] = copyTree(fn.getBody)
|
||||
instantiateBody(c, n, fn.typ.n, result, fn)
|
||||
if c.inGenericContext == 0:
|
||||
instantiateBody(c, n, fn.typ.n, result, fn)
|
||||
sideEffectsCheck(c, result)
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
|
|||
result = newNodeI(nkTypeOfExpr, n.info)
|
||||
let typExpr = semExprWithType(c, n, {efInTypeof})
|
||||
result.add typExpr
|
||||
result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc}))
|
||||
result.typ = makeTypeDesc(c, typExpr.typ)
|
||||
|
||||
type
|
||||
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn
|
||||
|
|
@ -86,9 +86,32 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
|||
result.add(filename)
|
||||
result.add(line)
|
||||
|
||||
proc toNode(t: PType, i: TLineInfo): PNode =
|
||||
result = newNodeIT(nkType, i, t)
|
||||
|
||||
const
|
||||
# these are types that use the bracket syntax for instantiation
|
||||
# they can be subjected to the type traits `genericHead` and
|
||||
# `Uninstantiated`
|
||||
tyUserDefinedGenerics* = {tyGenericInst, tyGenericInvocation,
|
||||
tyUserTypeClassInst}
|
||||
|
||||
tyMagicGenerics* = {tySet, tySequence, tyArray, tyOpenArray}
|
||||
|
||||
tyGenericLike* = tyUserDefinedGenerics +
|
||||
tyMagicGenerics +
|
||||
{tyCompositeTypeClass}
|
||||
|
||||
proc uninstantiate(t: PType): PType =
|
||||
result = case t.kind
|
||||
of tyMagicGenerics: t
|
||||
of tyUserDefinedGenerics: t.base
|
||||
of tyCompositeTypeClass: uninstantiate t.sons[1]
|
||||
else: t
|
||||
|
||||
proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
||||
let typ = operand.skipTypes({tyTypeDesc})
|
||||
case trait.sym.name.s.normalize
|
||||
var typ = operand.skipTypes({tyTypeDesc})
|
||||
case trait.sym.name.s
|
||||
of "name":
|
||||
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||
result.typ = newType(tyString, context)
|
||||
|
|
@ -97,6 +120,16 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
|
|||
result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
|
||||
result.typ = newType(tyInt, context)
|
||||
result.info = trait.info
|
||||
of "genericHead":
|
||||
var res = uninstantiate(typ)
|
||||
if res == typ and res.kind notin tyMagicGenerics:
|
||||
localError(trait.info,
|
||||
"genericHead expects a generic type. The given type was " &
|
||||
typeToString(typ))
|
||||
return newType(tyError, context).toNode(trait.info)
|
||||
result = res.base.toNode(trait.info)
|
||||
of "stripGenericParams":
|
||||
result = uninstantiate(typ).toNode(trait.info)
|
||||
else:
|
||||
internalAssert false
|
||||
|
||||
|
|
|
|||
|
|
@ -501,6 +501,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
#changeType(def.skipConv, typ, check=true)
|
||||
else:
|
||||
typ = skipIntLit(def.typ)
|
||||
if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass:
|
||||
typ = typ.lastSon
|
||||
if hasEmpty(typ):
|
||||
localError(def.info, errCannotInferTypeOfTheLiteral,
|
||||
($typ.kind).substr(2).toLowerAscii)
|
||||
|
|
@ -1554,6 +1556,16 @@ proc usesResult(n: PNode): bool =
|
|||
for c in n:
|
||||
if usesResult(c): return true
|
||||
|
||||
proc inferConceptStaticParam(c: PContext, inferred, n: PNode) =
|
||||
var typ = inferred.typ
|
||||
let res = semConstExpr(c, n)
|
||||
if not sameType(res.typ, typ.base):
|
||||
localError(n.info,
|
||||
"cannot infer the concept parameter '%s', due to a type mismatch. " &
|
||||
"attempt to equate '%s' and '%s'.",
|
||||
[inferred.renderTree, $res.typ, $typ.base])
|
||||
typ.n = res
|
||||
|
||||
proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# these must be last statements in a block:
|
||||
const
|
||||
|
|
@ -1605,10 +1617,21 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
n.typ = n.sons[i].typ
|
||||
return
|
||||
else:
|
||||
n.sons[i] = semExpr(c, n.sons[i])
|
||||
if c.inTypeClass > 0 and n[i].typ != nil:
|
||||
case n[i].typ.kind
|
||||
var expr = semExpr(c, n.sons[i], flags)
|
||||
n.sons[i] = expr
|
||||
if c.inTypeClass > 0 and expr.typ != nil:
|
||||
case expr.typ.kind
|
||||
of tyBool:
|
||||
if expr.kind == nkInfix and
|
||||
expr[0].kind == nkSym and
|
||||
expr[0].sym.name.s == "==":
|
||||
if expr[1].typ.isUnresolvedStatic:
|
||||
inferConceptStaticParam(c, expr[1], expr[2])
|
||||
continue
|
||||
elif expr[2].typ.isUnresolvedStatic:
|
||||
inferConceptStaticParam(c, expr[2], expr[1])
|
||||
continue
|
||||
|
||||
let verdict = semConstExpr(c, n[i])
|
||||
if verdict.intVal == 0:
|
||||
localError(result.info, "type class predicate failed")
|
||||
|
|
@ -1632,8 +1655,12 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||
else: discard
|
||||
if result.len == 1 and result.sons[0].kind != nkDefer:
|
||||
|
||||
if result.len == 1 and
|
||||
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
|
||||
result.sons[0].kind != nkDefer:
|
||||
result = result.sons[0]
|
||||
|
||||
when defined(nimfix):
|
||||
if result.kind == nkCommentStmt and not result.comment.isNil and
|
||||
not (result.comment[0] == '#' and result.comment[1] == '#'):
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
|||
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1)
|
||||
var base = semTypeNode(c, n.lastSon, nil)
|
||||
var base = semTypeNode(c, n.lastSon, nil).skipTypes({tyTypeDesc})
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
var isNilable = false
|
||||
# check every except the last is an object:
|
||||
|
|
@ -155,7 +155,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
|||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 1:
|
||||
result = newOrPrevType(tyVar, prev, c)
|
||||
var base = semTypeNode(c, n.sons[0], nil)
|
||||
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
|
||||
if base.kind == tyVar:
|
||||
localError(n.info, errVarVarTypeNotAllowed)
|
||||
base = base.sons[0]
|
||||
|
|
@ -185,16 +185,21 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
|||
for i in 0..1:
|
||||
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||
|
||||
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
|
||||
localError(n.info, errPureTypeMismatch)
|
||||
elif not rangeT[0].isOrdinalType:
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(rangeT[0]):
|
||||
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
||||
let hasUnknownTypes = c.inGenericContext > 0 and
|
||||
rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr
|
||||
|
||||
if not hasUnknownTypes:
|
||||
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
|
||||
localError(n.info, errPureTypeMismatch)
|
||||
elif not rangeT[0].isOrdinalType:
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(rangeT[0]):
|
||||
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
||||
|
||||
for i in 0..1:
|
||||
if hasGenericArguments(range[i]):
|
||||
result.n.addSon makeStaticExpr(c, range[i])
|
||||
result.flags.incl tfUnresolved
|
||||
else:
|
||||
result.n.addSon semConstExpr(c, range[i])
|
||||
|
||||
|
|
@ -227,7 +232,8 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||
if isRange(n): result = semRangeAux(c, n, nil)
|
||||
if isRange(n):
|
||||
result = semRangeAux(c, n, nil)
|
||||
else:
|
||||
let e = semExprWithType(c, n, {efDetermineType})
|
||||
if e.typ.kind == tyFromExpr:
|
||||
|
|
@ -765,6 +771,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
let owner = if typeClass.sym != nil: typeClass.sym
|
||||
else: getCurrOwner(c)
|
||||
var s = newSym(skType, finalTypId, owner, info)
|
||||
if sfExplain in owner.flags: s.flags.incl sfExplain
|
||||
if typId == nil: s.flags.incl(sfAnon)
|
||||
s.linkTo(typeClass)
|
||||
typeClass.flags.incl tfImplicitTypeParam
|
||||
|
|
@ -843,9 +850,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
|
||||
for i in 0 .. paramType.sonsLen - 2:
|
||||
if paramType.sons[i].kind == tyStatic:
|
||||
var x = copyNode(ast.emptyNode)
|
||||
x.typ = paramType.sons[i]
|
||||
result.rawAddSon makeTypeFromExpr(c, x) # aka 'tyUnknown'
|
||||
var staticCopy = paramType.sons[i].exactReplica
|
||||
staticCopy.flags.incl tfInferrableStatic
|
||||
result.rawAddSon staticCopy
|
||||
else:
|
||||
result.rawAddSon newTypeS(tyAnything, c)
|
||||
|
||||
|
|
@ -883,12 +890,13 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
|||
for i in 1 .. <paramType.len:
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
when false:
|
||||
|
||||
if paramType.base.lastSon.kind == tyUserTypeClass:
|
||||
let expanded = instGenericContainer(c, info, paramType,
|
||||
allowMetaTypes = true)
|
||||
result = liftingWalk(expanded, true)
|
||||
|
||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true))
|
||||
|
||||
of tyGenericParam:
|
||||
|
|
@ -1223,6 +1231,13 @@ proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
|
|||
result.sym = prev.sym
|
||||
assignType(prev, result)
|
||||
|
||||
proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
|
||||
if n.kind == nkType:
|
||||
result = symFromType(n.typ, n.info)
|
||||
else:
|
||||
localError(n.info, errTypeExpected)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = nil
|
||||
when defined(nimsuggest):
|
||||
|
|
@ -1237,6 +1252,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
||||
fixupTypeOf(c, prev, typExpr)
|
||||
result = typExpr.typ
|
||||
if result.kind == tyTypeDesc: result.flags.incl tfExplicit
|
||||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else:
|
||||
|
|
@ -1312,7 +1328,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = semTypeNode(c, whenResult, prev)
|
||||
of nkBracketExpr:
|
||||
checkMinSonsLen(n, 2)
|
||||
var s = semTypeIdent(c, n.sons[0])
|
||||
var head = n.sons[0]
|
||||
var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
|
||||
else: symFromExpectedTypeNode(c, semExpr(c, head))
|
||||
case s.magic
|
||||
of mArray: result = semArray(c, n, prev)
|
||||
of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev)
|
||||
|
|
@ -1344,6 +1362,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
else: result = semGeneric(c, n, s, prev)
|
||||
of nkDotExpr:
|
||||
let typeExpr = semExpr(c, n)
|
||||
if typeExpr.typ.kind == tyFromExpr:
|
||||
return typeExpr.typ
|
||||
if typeExpr.typ.kind != tyTypeDesc:
|
||||
localError(n.info, errTypeExpected)
|
||||
result = errorType(c)
|
||||
|
|
@ -1403,7 +1423,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
of nkDistinctTy: result = semDistinct(c, n, prev)
|
||||
of nkStaticTy:
|
||||
result = newOrPrevType(tyStatic, prev, c)
|
||||
var base = semTypeNode(c, n.sons[0], nil)
|
||||
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
|
||||
result.rawAddSon(base)
|
||||
result.flags.incl tfHasStatic
|
||||
of nkIteratorTy:
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ proc isTypeParam(n: PNode): bool =
|
|||
proc hasGenericArguments*(n: PNode): bool =
|
||||
if n.kind == nkSym:
|
||||
return n.sym.kind == skGenericParam or
|
||||
tfInferrableStatic in n.sym.typ.flags or
|
||||
(n.sym.kind == skType and
|
||||
n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
|
||||
else:
|
||||
|
|
@ -144,7 +145,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
|
|||
if isTypeParam(n[i]): needsFixing = true
|
||||
if needsFixing:
|
||||
n.sons[0] = newSymNode(n.sons[0].sym.owner)
|
||||
return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
|
||||
return cl.c.semOverloadedCall(cl.c, n, n, {skProc}, {})
|
||||
|
||||
for i in 0 .. <n.safeLen:
|
||||
n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
|
||||
|
|
@ -403,6 +404,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
case t.kind
|
||||
of tyGenericInvocation:
|
||||
result = handleGenericInvocation(cl, t)
|
||||
if result.lastSon.kind == tyUserTypeClass:
|
||||
result.kind = tyUserTypeClassInst
|
||||
|
||||
of tyGenericBody:
|
||||
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
||||
|
|
@ -444,10 +447,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
|||
elif t.sons[0].kind != tyNone:
|
||||
result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
|
||||
|
||||
of tyUserTypeClass:
|
||||
of tyUserTypeClass, tyStatic:
|
||||
result = t
|
||||
|
||||
of tyGenericInst:
|
||||
of tyGenericInst, tyUserTypeClassInst:
|
||||
bailout()
|
||||
result = instCopyType(cl, t)
|
||||
idTablePut(cl.localCache, t, result)
|
||||
|
|
@ -501,8 +504,9 @@ proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo;
|
|||
result.owner = owner
|
||||
|
||||
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
|
||||
owner: PSym): PNode =
|
||||
owner: PSym, allowMetaTypes = false): PNode =
|
||||
var cl = initTypeVars(p, pt, n.info, owner)
|
||||
cl.allowMetaTypes = allowMetaTypes
|
||||
pushInfoContext(n.info)
|
||||
result = replaceTypeVarsN(cl, n)
|
||||
popInfoContext()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,13 @@ type
|
|||
TCandidateState* = enum
|
||||
csEmpty, csMatch, csNoMatch
|
||||
|
||||
CandidateErrors* = seq[(PSym,int)]
|
||||
CandidateError* = object
|
||||
sym*: PSym
|
||||
unmatchedVarParam*: int
|
||||
diagnostics*: seq[string]
|
||||
|
||||
CandidateErrors* = seq[CandidateError]
|
||||
|
||||
TCandidate* = object
|
||||
c*: PContext
|
||||
exactMatches*: int # also misused to prefer iters over procs
|
||||
|
|
@ -49,11 +55,20 @@ type
|
|||
# a distrinct type
|
||||
typedescMatched*: bool
|
||||
isNoCall*: bool # misused for generic type instantiations C[T]
|
||||
inferredTypes: seq[PType] # inferred types during the current signature
|
||||
# matching. they will be reset if the matching
|
||||
# is not successful. may replace the bindings
|
||||
# table in the future.
|
||||
diagnostics*: seq[string] # when this is not nil, the matching process
|
||||
# will collect extra diagnostics that will be
|
||||
# displayed to the user.
|
||||
# triggered when overload resolution fails
|
||||
# or when the explain pragma is used. may be
|
||||
# triggered with an idetools command in the
|
||||
# future.
|
||||
mutabilityProblem*: uint8 # tyVar mismatch
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||
# user if overload resolution fails
|
||||
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
|
|
@ -101,7 +116,7 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} =
|
|||
idTablePut(c.bindings, key, val.skipIntLit)
|
||||
|
||||
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||
binding: PNode, calleeScope = -1) =
|
||||
binding: PNode, calleeScope = -1, diagnostics = false) =
|
||||
initCandidateAux(ctx, c, callee.typ)
|
||||
c.calleeSym = callee
|
||||
if callee.kind in skProcKinds and calleeScope == -1:
|
||||
|
|
@ -116,9 +131,9 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
|||
c.calleeScope = 1
|
||||
else:
|
||||
c.calleeScope = calleeScope
|
||||
c.diagnostics = if diagnostics: @[] else: nil
|
||||
c.magic = c.calleeSym.magic
|
||||
initIdTable(c.bindings)
|
||||
c.errors = nil
|
||||
if binding != nil and callee.kind in routineKinds:
|
||||
var typeParams = callee.ast[genericParamsPos]
|
||||
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
|
||||
|
|
@ -572,19 +587,22 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
|||
result = isNone
|
||||
|
||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
ff, a: PType): TTypeRelation =
|
||||
var body = ff.skipTypes({tyUserTypeClassInst})
|
||||
ff, a: PType): PType =
|
||||
var
|
||||
typeClass = ff.skipTypes({tyUserTypeClassInst})
|
||||
body = typeClass.n[3]
|
||||
if c.inTypeClass > 4:
|
||||
localError(body.n[3].info, $body.n[3] & " too nested for type matching")
|
||||
return isNone
|
||||
localError(body.info, $body & " too nested for type matching")
|
||||
return nil
|
||||
|
||||
openScope(c)
|
||||
inc c.inTypeClass
|
||||
|
||||
defer:
|
||||
dec c.inTypeClass
|
||||
closeScope(c)
|
||||
|
||||
var typeParams: seq[(PSym, PType)]
|
||||
|
||||
if ff.kind == tyUserTypeClassInst:
|
||||
for i in 1 .. <(ff.len - 1):
|
||||
var
|
||||
|
|
@ -593,44 +611,104 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
|||
param: PSym
|
||||
|
||||
template paramSym(kind): untyped =
|
||||
newSym(kind, typeParamName, body.sym, body.sym.info)
|
||||
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
|
||||
|
||||
case typ.kind
|
||||
of tyStatic:
|
||||
param = paramSym skConst
|
||||
param.typ = typ.base
|
||||
param.ast = typ.n
|
||||
of tyUnknown:
|
||||
param = paramSym skVar
|
||||
param.typ = typ
|
||||
else:
|
||||
param = paramSym skType
|
||||
param.typ = makeTypeDesc(c, typ)
|
||||
block addTypeParam:
|
||||
for prev in typeParams:
|
||||
if prev[1].id == typ.id:
|
||||
param = paramSym prev[0].kind
|
||||
param.typ = prev[0].typ
|
||||
break addTypeParam
|
||||
|
||||
case typ.kind
|
||||
of tyStatic:
|
||||
param = paramSym skConst
|
||||
param.typ = typ.exactReplica
|
||||
if typ.n == nil:
|
||||
param.typ.flags.incl tfInferrableStatic
|
||||
else:
|
||||
param.ast = typ.n
|
||||
of tyUnknown:
|
||||
param = paramSym skVar
|
||||
param.typ = typ.exactReplica
|
||||
else:
|
||||
param = paramSym skType
|
||||
param.typ = if typ.isMetaType:
|
||||
c.newTypeWithSons(tyInferred, @[typ])
|
||||
else:
|
||||
makeTypeDesc(c, typ)
|
||||
|
||||
typeParams.safeAdd((param, typ))
|
||||
|
||||
addDecl(c, param)
|
||||
#echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind
|
||||
|
||||
for param in body.n[0]:
|
||||
for param in typeClass.n[0]:
|
||||
var
|
||||
dummyName: PNode
|
||||
dummyType: PType
|
||||
|
||||
if param.kind == nkVarTy:
|
||||
let modifier = case param.kind
|
||||
of nkVarTy: tyVar
|
||||
of nkRefTy: tyRef
|
||||
of nkPtrTy: tyPtr
|
||||
of nkStaticTy: tyStatic
|
||||
of nkTypeOfExpr: tyTypeDesc
|
||||
else: tyNone
|
||||
|
||||
if modifier != tyNone:
|
||||
dummyName = param[0]
|
||||
dummyType = if a.kind != tyVar: makeVarType(c, a) else: a
|
||||
dummyType = c.makeTypeWithModifier(modifier, a)
|
||||
if modifier == tyTypeDesc: dummyType.flags.incl tfExplicit
|
||||
else:
|
||||
dummyName = param
|
||||
dummyType = a
|
||||
|
||||
internalAssert dummyName.kind == nkIdent
|
||||
var dummyParam = newSym(skVar, dummyName.ident, body.sym, body.sym.info)
|
||||
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
|
||||
dummyName.ident, typeClass.sym, typeClass.sym.info)
|
||||
dummyParam.typ = dummyType
|
||||
addDecl(c, dummyParam)
|
||||
#echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||
if checkedBody == nil: return isNone
|
||||
return isGeneric
|
||||
var
|
||||
oldWriteHook: type(writelnHook)
|
||||
diagnostics: seq[string]
|
||||
errorPrefix: string
|
||||
flags: TExprFlags = {}
|
||||
collectDiagnostics = m.diagnostics != nil or
|
||||
sfExplain in typeClass.sym.flags
|
||||
|
||||
if collectDiagnostics:
|
||||
oldWriteHook = writelnHook
|
||||
# XXX: we can't write to m.diagnostics directly, because
|
||||
# Nim doesn't support capturing var params in closures
|
||||
diagnostics = @[]
|
||||
flags = {efExplain}
|
||||
writelnHook = proc (s: string) =
|
||||
if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":"
|
||||
let msg = s.replace("Error:", errorPrefix)
|
||||
if oldWriteHook != nil: oldWriteHook msg
|
||||
diagnostics.add msg
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.copyTree, flags)
|
||||
|
||||
if collectDiagnostics:
|
||||
writelnHook = oldWriteHook
|
||||
for msg in diagnostics: m.diagnostics.safeAdd msg
|
||||
|
||||
if checkedBody == nil: return nil
|
||||
|
||||
# The inferrable type params have been identified during the semTryExpr above.
|
||||
# We need to put them in the current sigmatch's binding table in order for them
|
||||
# to be resolvable while matching the rest of the parameters
|
||||
for p in typeParams:
|
||||
put(m, p[1], p[0].typ)
|
||||
|
||||
if ff.kind == tyUserTypeClassInst:
|
||||
result = generateTypeInstance(c, m.bindings, typeClass.sym.info, ff)
|
||||
else:
|
||||
result = copyType(ff, ff.owner, true)
|
||||
|
||||
result.n = checkedBody
|
||||
|
||||
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
|
||||
if rules.kind == nkWith:
|
||||
|
|
@ -649,16 +727,125 @@ proc maybeSkipDistinct(t: PType, callee: PSym): PType =
|
|||
else:
|
||||
result = t
|
||||
|
||||
proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
|
||||
proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
|
||||
allowUnresolved = false): PNode =
|
||||
# Consider this example:
|
||||
# type Value[N: static[int]] = object
|
||||
# proc foo[N](a: Value[N], r: range[0..(N-1)])
|
||||
# Here, N-1 will be initially nkStaticExpr that can be evaluated only after
|
||||
# N is bound to a concrete value during the matching of the first param.
|
||||
# This proc is used to evaluate such static expressions.
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil)
|
||||
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil,
|
||||
allowMetaTypes = allowUnresolved)
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
# This is a simple integer arithimetic equation solver,
|
||||
# capable of deriving the value of a static parameter in
|
||||
# expressions such as (N + 5) / 2 = rhs
|
||||
#
|
||||
# Preconditions:
|
||||
#
|
||||
# * The input of this proc must be semantized
|
||||
# - all templates should be expanded
|
||||
# - aby constant folding possible should already be performed
|
||||
#
|
||||
# * There must be exactly one unresolved static parameter
|
||||
#
|
||||
# Result:
|
||||
#
|
||||
# The proc will return the inferred static type with the `n` field
|
||||
# populated with the inferred value.
|
||||
#
|
||||
# `nil` will be returned if the inference was not possible
|
||||
#
|
||||
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
|
||||
case lhs[0].sym.magic
|
||||
of mUnaryLt:
|
||||
return inferStaticParam(lhs[1], rhs + 1)
|
||||
|
||||
of mAddI, mAddU, mInc, mSucc:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[2], rhs - lhs[1].intVal)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
|
||||
|
||||
of mDec, mSubI, mSubU, mPred:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal - rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
|
||||
|
||||
of mMulI, mMulU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if rhs mod lhs[1].intVal == 0:
|
||||
return inferStaticParam(lhs[2], rhs div lhs[1].intVal)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
if rhs mod lhs[2].intVal == 0:
|
||||
return inferStaticParam(lhs[1], rhs div lhs[2].intVal)
|
||||
|
||||
of mDivI, mDivU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if lhs[1].intVal mod rhs == 0:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal div rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
|
||||
|
||||
of mShlI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shr lhs[2].intVal)
|
||||
|
||||
of mShrI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shl lhs[2].intVal)
|
||||
|
||||
of mUnaryMinusI:
|
||||
return inferStaticParam(lhs[1], -rhs)
|
||||
|
||||
of mUnaryPlusI, mToInt, mToBiggestInt:
|
||||
return inferStaticParam(lhs[1], rhs)
|
||||
|
||||
else: discard
|
||||
|
||||
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
|
||||
lhs.typ.n = newIntNode(nkIntLit, rhs)
|
||||
return lhs.typ
|
||||
|
||||
return nil
|
||||
|
||||
proc failureToInferStaticParam(n: PNode) =
|
||||
let staticParam = n.findUnresolvedStatic
|
||||
let name = if staticParam != nil: staticParam.sym.name.s
|
||||
else: "unknown"
|
||||
localError(n.info, errCannotInferStaticParam, name)
|
||||
|
||||
proc inferStaticsInRange(c: var TCandidate,
|
||||
inferred, concrete: PType): TTypeRelation =
|
||||
let lowerBound = tryResolvingStaticExpr(c, inferred.n[0],
|
||||
allowUnresolved = true)
|
||||
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
|
||||
allowUnresolved = true)
|
||||
|
||||
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
|
||||
var exp = e
|
||||
var rhs = r
|
||||
var inferred = inferStaticParam(exp, rhs)
|
||||
if inferred != nil:
|
||||
put(c, inferred, inferred)
|
||||
return isGeneric
|
||||
else:
|
||||
failureToInferStaticParam exp
|
||||
|
||||
if lowerBound.kind == nkIntLit:
|
||||
if upperBound.kind == nkIntLit:
|
||||
if lengthOrd(concrete) == upperBound.intVal - lowerBound.intVal + 1:
|
||||
return isGeneric
|
||||
else:
|
||||
return isNone
|
||||
doInferStatic(c, upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
|
||||
elif upperBound.kind == nkIntLit:
|
||||
doInferStatic(c, lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
|
||||
|
||||
template subtypeCheck() =
|
||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||
result = isNone
|
||||
|
|
@ -689,8 +876,49 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
|
||||
assert(aOrig != nil)
|
||||
|
||||
var
|
||||
useTypeLoweringRuleInTypeClass = c.c.inTypeClass > 0 and
|
||||
not c.isNoCall and
|
||||
f.kind != tyTypeDesc and
|
||||
tfExplicit notin aOrig.flags
|
||||
|
||||
aOrig = if useTypeLoweringRuleInTypeClass:
|
||||
aOrig.skipTypes({tyTypeDesc, tyFieldAccessor})
|
||||
else:
|
||||
aOrig
|
||||
|
||||
if aOrig.kind == tyInferred:
|
||||
let prev = aOrig.previouslyInferred
|
||||
if prev != nil:
|
||||
return typeRel(c, f, prev)
|
||||
else:
|
||||
var candidate = f
|
||||
|
||||
case f.kind
|
||||
of tyGenericParam:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
if prev != nil: candidate = prev
|
||||
of tyFromExpr:
|
||||
let computedType = tryResolvingStaticExpr(c, f.n).typ
|
||||
case computedType.kind
|
||||
of tyTypeDesc:
|
||||
candidate = computedType.base
|
||||
of tyStatic:
|
||||
candidate = computedType
|
||||
else:
|
||||
localError(f.n.info, errTypeExpected)
|
||||
else:
|
||||
discard
|
||||
|
||||
result = typeRel(c, aOrig.base, candidate)
|
||||
if result != isNone:
|
||||
c.inferredTypes.safeAdd aOrig
|
||||
aOrig.sons.add candidate
|
||||
result = isEqual
|
||||
return
|
||||
|
||||
# var and static arguments match regular modifier-free types
|
||||
let a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||
var a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
|
||||
# XXX: Theoretically, maybeSkipDistinct could be called before we even
|
||||
# start the param matching process. This could be done in `prepareOperand`
|
||||
# for example, but unfortunately `prepareOperand` is not called in certain
|
||||
|
|
@ -702,6 +930,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||
return typeRel(c, f, lastSon(a))
|
||||
|
||||
if a.isResolvedUserTypeClass:
|
||||
return typeRel(c, f, a.lastSon)
|
||||
|
||||
template bindingRet(res) =
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
|
|
@ -807,6 +1038,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
case a.kind
|
||||
of tyArray:
|
||||
var fRange = f.sons[0]
|
||||
var aRange = a.sons[0]
|
||||
if fRange.kind == tyGenericParam:
|
||||
var prev = PType(idTableGet(c.bindings, fRange))
|
||||
if prev == nil:
|
||||
|
|
@ -814,28 +1046,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
fRange = a
|
||||
else:
|
||||
fRange = prev
|
||||
result = typeRel(c, f.sons[1], a.sons[1])
|
||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
||||
a.sons[1].skipTypes({tyTypeDesc}))
|
||||
if result < isGeneric: return isNone
|
||||
if rangeHasStaticIf(fRange):
|
||||
if tfUnresolved in fRange.flags:
|
||||
# This is a range from an array instantiated with a generic
|
||||
# static param. We must extract the static param here and bind
|
||||
# it to the size of the currently supplied array.
|
||||
var
|
||||
rangeStaticT = fRange.getStaticTypeFromRange
|
||||
replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
|
||||
inputUpperBound = a.sons[0].n[1].intVal
|
||||
# we must correct for the off-by-one discrepancy between
|
||||
# ranges and static params:
|
||||
replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
|
||||
put(c, rangeStaticT, replacementT)
|
||||
return isGeneric
|
||||
|
||||
let len = tryResolvingStaticExpr(c, fRange.n[1])
|
||||
if len.kind == nkIntLit and len.intVal+1 == lengthOrd(a):
|
||||
return # if we get this far, the result is already good
|
||||
else:
|
||||
return isNone
|
||||
|
||||
if fRange.rangeHasUnresolvedStatic:
|
||||
return inferStaticsInRange(c, fRange, a)
|
||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
||||
return inferStaticsInRange(c, aRange, f)
|
||||
elif lengthOrd(fRange) != lengthOrd(a):
|
||||
result = isNone
|
||||
else: discard
|
||||
|
|
@ -1111,11 +1329,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
else:
|
||||
return isNone
|
||||
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
considerPreviousT:
|
||||
result = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if result == isGeneric:
|
||||
put(c, f, a)
|
||||
of tyUserTypeClassInst, tyUserTypeClass:
|
||||
if f.isResolvedUserTypeClass:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
else:
|
||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if matched != nil:
|
||||
bindConcreteTypeToUserTypeClass(matched, a)
|
||||
put(c, f, matched)
|
||||
result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
of tyCompositeTypeClass:
|
||||
considerPreviousT:
|
||||
|
|
@ -1212,6 +1436,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
# XXX endless recursion?
|
||||
#result = typeRel(c, prev, aOrig)
|
||||
result = isNone
|
||||
|
||||
of tyInferred:
|
||||
let prev = f.previouslyInferred
|
||||
if prev != nil:
|
||||
result = typeRel(c, prev, a)
|
||||
else:
|
||||
result = typeRel(c, f.base, a)
|
||||
if result != isNone:
|
||||
c.inferredTypes.safeAdd f
|
||||
f.sons.add a
|
||||
|
||||
of tyTypeDesc:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
if prev == nil:
|
||||
|
|
@ -1355,12 +1590,12 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
|||
of isEqual: inc(m.exactMatches)
|
||||
of isNone: discard
|
||||
|
||||
proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
argSemantized, argOrig: PNode): PNode =
|
||||
var
|
||||
fMaybeStatic = f.skipTypes({tyDistinct})
|
||||
arg = argSemantized
|
||||
argType = argType
|
||||
a = a
|
||||
c = m.c
|
||||
|
||||
if tfHasStatic in fMaybeStatic.flags:
|
||||
|
|
@ -1370,15 +1605,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
|
||||
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder
|
||||
# and finally start using tyTypedesc for generic types properly.
|
||||
if argType.kind == tyGenericParam and tfWildcard in argType.flags:
|
||||
argType.assignType(f)
|
||||
# put(m.bindings, f, argType)
|
||||
if a.kind == tyGenericParam and tfWildcard in a.flags:
|
||||
a.assignType(f)
|
||||
# put(m.bindings, f, a)
|
||||
return argSemantized
|
||||
|
||||
if argType.kind == tyStatic:
|
||||
if a.kind == tyStatic:
|
||||
if m.callee.kind == tyGenericBody and
|
||||
argType.n == nil and
|
||||
tfGenericTypeParam notin argType.flags:
|
||||
a.n == nil and
|
||||
tfGenericTypeParam notin a.flags:
|
||||
return newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
|
||||
else:
|
||||
var evaluated = c.semTryConstExpr(c, arg)
|
||||
|
|
@ -1386,9 +1621,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
arg.typ = newTypeS(tyStatic, c)
|
||||
arg.typ.sons = @[evaluated.typ]
|
||||
arg.typ.n = evaluated
|
||||
argType = arg.typ
|
||||
a = arg.typ
|
||||
|
||||
var a = argType
|
||||
var r = typeRel(m, f, a)
|
||||
|
||||
if r != isNone and m.calleeSym != nil and
|
||||
|
|
@ -1830,6 +2064,10 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
|
|||
def = implicitConv(nkHiddenStdConv, formal.typ, def, m, c)
|
||||
setSon(m.call, formal.position + 1, def)
|
||||
inc(f)
|
||||
# forget all inferred types if the overload matching failed
|
||||
if m.state == csNoMatch:
|
||||
for t in m.inferredTypes:
|
||||
if t.sonsLen > 1: t.sons.setLen 1
|
||||
|
||||
proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||
var m: TCandidate
|
||||
|
|
|
|||
|
|
@ -55,16 +55,17 @@ const
|
|||
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
|
||||
# replace with typedescX
|
||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias}
|
||||
tyTypeDesc, tyAlias, tyInferred}
|
||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc,
|
||||
tyAlias}
|
||||
tyAlias, tyInferred}
|
||||
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal, tyTypeDesc,
|
||||
tyAlias}
|
||||
tyAlias, tyInferred}
|
||||
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias}
|
||||
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias}
|
||||
|
||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias}
|
||||
tyTypeDesc, tyAlias, tyInferred}
|
||||
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias,
|
||||
tyInferred}
|
||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyTypeDesc, tyAlias,
|
||||
tyInferred}
|
||||
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||
typedescInst* = abstractInst + {tyTypeDesc}
|
||||
|
|
@ -182,7 +183,7 @@ proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
|
|||
if result: return
|
||||
if not containsOrIncl(marker, t.id):
|
||||
case t.kind
|
||||
of tyGenericInst, tyGenericBody, tyAlias:
|
||||
of tyGenericInst, tyGenericBody, tyAlias, tyInferred:
|
||||
result = iterOverTypeAux(marker, lastSon(t), iter, closure)
|
||||
else:
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
|
|
@ -410,12 +411,19 @@ const
|
|||
"unused0", "unused1",
|
||||
"unused2", "varargs[$1]", "unused", "Error Type",
|
||||
"BuiltInTypeClass", "UserTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass", "inferred",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
|
||||
"void"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
|
||||
|
||||
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
|
||||
tc.sons.safeAdd concrete
|
||||
tc.flags.incl tfResolved
|
||||
|
||||
template isResolvedUserTypeClass*(t: PType): bool =
|
||||
tfResolved in t.flags
|
||||
|
||||
proc addTypeFlags(name: var string, typ: PType) {.inline.} =
|
||||
if tfNotNil in typ.flags: name.add(" not nil")
|
||||
|
||||
|
|
@ -460,6 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
if t.n != nil: result.add "(" & renderTree(t.n) & ")"
|
||||
of tyUserTypeClass:
|
||||
internalAssert t.sym != nil and t.sym.owner != nil
|
||||
if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
|
||||
return t.sym.owner.name.s
|
||||
of tyBuiltInTypeClass:
|
||||
result = case t.base.kind:
|
||||
|
|
@ -476,6 +485,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
of tyTuple: "tuple"
|
||||
of tyOpenArray: "openarray"
|
||||
else: typeToStr[t.base.kind]
|
||||
of tyInferred:
|
||||
let concrete = t.previouslyInferred
|
||||
if concrete != nil: result = typeToString(concrete)
|
||||
else: result = "inferred[" & typeToString(t.base) & "]"
|
||||
of tyUserTypeClassInst:
|
||||
let body = t.base
|
||||
result = body.sym.name.s & "["
|
||||
|
|
@ -971,7 +984,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
|||
result = sameTypeOrNilAux(a.sons[0], b.sons[0], c) and
|
||||
sameValue(a.n.sons[0], b.n.sons[0]) and
|
||||
sameValue(a.n.sons[1], b.n.sons[1])
|
||||
of tyGenericInst, tyAlias: discard
|
||||
of tyGenericInst, tyAlias, tyInferred:
|
||||
cycleCheck()
|
||||
result = sameTypeAux(a.lastSon, b.lastSon, c)
|
||||
of tyNone: result = false
|
||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("sameFlags")
|
||||
|
||||
|
|
@ -1118,7 +1133,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
|||
result = nil
|
||||
of tyOrdinal:
|
||||
if kind != skParam: result = t
|
||||
of tyGenericInst, tyDistinct, tyAlias:
|
||||
of tyGenericInst, tyDistinct, tyAlias, tyInferred:
|
||||
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
||||
of tyRange:
|
||||
if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
|
||||
|
|
@ -1305,14 +1320,20 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
|||
if result < 0: return
|
||||
if a < maxAlign: a = maxAlign
|
||||
result = align(result, a)
|
||||
of tyInferred:
|
||||
if typ.len > 1:
|
||||
result = computeSizeAux(typ.lastSon, a)
|
||||
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias:
|
||||
result = computeSizeAux(lastSon(typ), a)
|
||||
of tyTypeClasses:
|
||||
result = if typ.isResolvedUserTypeClass: computeSizeAux(typ.lastSon, a)
|
||||
else: szUnknownSize
|
||||
of tyTypeDesc:
|
||||
result = computeSizeAux(typ.base, a)
|
||||
of tyForward: return szIllegalRecursion
|
||||
of tyStatic:
|
||||
if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
|
||||
else: result = szUnknownSize
|
||||
result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
|
||||
else: szUnknownSize
|
||||
else:
|
||||
#internalError("computeSizeAux()")
|
||||
result = szUnknownSize
|
||||
|
|
@ -1333,18 +1354,17 @@ proc getSize(typ: PType): BiggestInt =
|
|||
if result < 0: internalError("getSize: " & $typ.kind)
|
||||
|
||||
proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
|
||||
if t.kind == tyStatic:
|
||||
case t.kind
|
||||
of tyStatic:
|
||||
return t.n == nil
|
||||
|
||||
if t.kind == tyTypeDesc:
|
||||
of tyTypeDesc:
|
||||
if t.base.kind == tyNone: return true
|
||||
if containsGenericTypeIter(t.base, closure): return true
|
||||
return false
|
||||
|
||||
if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
|
||||
of GenericTypes + tyTypeClasses + {tyFromExpr}:
|
||||
return true
|
||||
|
||||
return false
|
||||
else:
|
||||
return false
|
||||
|
||||
proc containsGenericType*(t: PType): bool =
|
||||
result = iterOverType(t, containsGenericTypeIter, nil)
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
|||
result.add mapTypeToAst(t.sons[i], info)
|
||||
else:
|
||||
result = mapTypeToAstX(t.lastSon, info, inst, allowRecursion)
|
||||
of tyGenericBody, tyOrdinal, tyUserTypeClassInst:
|
||||
of tyGenericBody, tyOrdinal:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
of tyDistinct:
|
||||
if inst:
|
||||
|
|
@ -285,15 +285,19 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
|||
of tyProxy: result = atomicType("error", mNone)
|
||||
of tyBuiltInTypeClass:
|
||||
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
|
||||
of tyUserTypeClass:
|
||||
result = mapTypeToBracket("concept", mNone, t, info)
|
||||
result.add t.n.copyTree
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
if t.isResolvedUserTypeClass:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
else:
|
||||
result = mapTypeToBracket("concept", mNone, t, info)
|
||||
result.add t.n.copyTree
|
||||
of tyCompositeTypeClass:
|
||||
result = mapTypeToBracket("compositeTypeClass", mNone, t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", mAnd, t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", mOr, t, info)
|
||||
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
|
||||
of tyAnything: result = atomicType("anything", mNone)
|
||||
of tyInferred: internalAssert false
|
||||
of tyStatic, tyFromExpr, tyFieldAccessor:
|
||||
if inst:
|
||||
if t.n != nil: result = t.n.copyTree
|
||||
|
|
|
|||
|
|
@ -1678,7 +1678,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
|||
elif sfImportc in s.flags: c.importcSym(n.info, s)
|
||||
genLit(c, n, dest)
|
||||
of skConst:
|
||||
gen(c, s.ast, dest)
|
||||
let constVal = if s.ast != nil: s.ast else: s.typ.n
|
||||
gen(c, constVal, dest)
|
||||
of skEnumField:
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
if s.position >= low(int16) and s.position <= high(int16):
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ type
|
|||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||
wAsmNoStackFrame,
|
||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
|
||||
wPartial,
|
||||
wPartial, wExplain,
|
||||
|
||||
wAuto, wBool, wCatch, wChar, wClass,
|
||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||
|
|
@ -152,7 +152,7 @@ const
|
|||
"computedgoto", "injectstmt", "experimental",
|
||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||
"guard", "locks", "partial",
|
||||
"guard", "locks", "partial", "explain",
|
||||
|
||||
"auto", "bool", "catch", "char", "class",
|
||||
"const_cast", "default", "delete", "double",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue