diff options
author | Zahary Karadjov <zahary@gmail.com> | 2013-09-03 03:14:56 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2013-09-03 03:14:56 +0300 |
commit | 6082595e968f000b5089b1db7e72ad55bbf3fac3 (patch) | |
tree | 06a76e725c59524b5e7ab23e8c5f1a7c1bef5e54 /compiler | |
parent | 39da6979add895cf58e9c6f883ef8df465975cd6 (diff) | |
parent | c8c8d2035af189bdf63b39d4e47266a6e67c38b9 (diff) | |
download | Nim-6082595e968f000b5089b1db7e72ad55bbf3fac3.tar.gz |
Merge branch 'type-classes' into upstream
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 13 | ||||
-rw-r--r-- | compiler/astalgo.nim | 13 | ||||
-rw-r--r-- | compiler/evals.nim | 41 | ||||
-rw-r--r-- | compiler/idents.nim | 1 | ||||
-rw-r--r-- | compiler/lexer.nim | 4 | ||||
-rw-r--r-- | compiler/msgs.nim | 3 | ||||
-rw-r--r-- | compiler/parser.nim | 38 | ||||
-rw-r--r-- | compiler/pragmas.nim | 7 | ||||
-rw-r--r-- | compiler/sem.nim | 61 | ||||
-rw-r--r-- | compiler/semcall.nim | 145 | ||||
-rw-r--r-- | compiler/semdata.nim | 6 | ||||
-rw-r--r-- | compiler/semexprs.nim | 124 | ||||
-rw-r--r-- | compiler/semmagic.nim | 1 | ||||
-rw-r--r-- | compiler/semstmts.nim | 11 | ||||
-rw-r--r-- | compiler/semtypes.nim | 18 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 8 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 123 | ||||
-rw-r--r-- | compiler/types.nim | 1 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 16 |
19 files changed, 430 insertions, 204 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index bb06e7163..6e0cafd74 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -178,6 +178,7 @@ type nkIncludeStmt, # an include statement nkBindStmt, # a bind statement nkMixinStmt, # a mixin statement + nkUsingStmt, # an using statement nkCommentStmt, # a comment statement nkStmtListExpr, # a statement list followed by an expr; this is used # to allow powerful multi-line templates @@ -190,6 +191,7 @@ type nkTypeOfExpr, # type(1+2) nkObjectTy, # object body nkTupleTy, # tuple body + nkTypeClassTy, # user-defined type class nkRecList, # list of object parts nkRecCase, # case section of object nkRecWhen, # when section of object @@ -215,7 +217,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # already 30 flags! + TSymFlag* = enum # already 32 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -352,6 +354,8 @@ type # efficiency nfTransf, # node has been transformed nfSem # node has been checked for semantics + nfDelegate # the call can use a delegator + nfExprCall # this is an attempt to call a regular expression TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23) @@ -616,6 +620,7 @@ type TScope* = object depthLevel*: int symbols*: TStrTable + usingSyms*: seq[PNode] parent*: PScope PScope* = ref TScope @@ -688,6 +693,7 @@ type # for enum types a list of symbols # for tyInt it can be the int literal # for procs and tyGenericBody, it's the + # the body of the user-defined type class # formal param list # else: unused destructor*: PSym # destructor. warning: nil here may not necessary @@ -700,6 +706,7 @@ type # -1 means that the size is unkwown align*: int # the type's alignment requirements loc*: TLoc + testeeName*: PIdent # the test variable in user-defined type classes TPair*{.final.} = object key*, val*: PObject @@ -771,7 +778,8 @@ const tyProc, tyString, tyError} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, skMacro, skTemplate, skConverter, skEnumField, skLet, skStub} - PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst} + PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, + nfAllConst, nfDelegate} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 @@ -1074,6 +1082,7 @@ proc assignType(dest, src: PType) = dest.size = src.size dest.align = src.align dest.destructor = src.destructor + dest.testeeName = src.testeeName # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index fd6774e7a..6c48dd00f 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -430,11 +430,14 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) appf(result, "$N$1}", [spaces(indent)]) -proc debug(n: PSym) = - #writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) - writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [ - toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), - flagsToStr(n.loc.flags)]))) +proc debug(n: PSym) = + if n == nil: + writeln(stdout, "null") + else: + #writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) + writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [ + toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), + flagsToStr(n.loc.flags)]))) proc debug(n: PType) = writeln(stdout, ropeToStr(debugType(n))) diff --git a/compiler/evals.nim b/compiler/evals.nim index 053068ea4..be6f625ec 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -53,7 +53,8 @@ type features: TSandboxFlags globals*: TIdNodeTable # state of global vars getType*: proc(n: PNode): PNode {.closure.} - + handleIsOperator*: proc(n: PNode): PNode {.closure.} + PEvalContext* = ref TEvalContext TEvalFlag = enum @@ -916,33 +917,6 @@ proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode = else: internalAssert false -proc evalIsOp*(n: PNode): PNode = - InternalAssert n.sonsLen == 3 and - n[1].kind == nkSym and n[1].sym.kind == skType and - n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - - let t1 = n[1].sym.typ - - if n[2].kind in {nkStrLit..nkTripleStrLit}: - case n[2].strVal.normalize - of "closure": - let t = skipTypes(t1, abstractRange) - result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and - tfIterator notin t.flags)) - of "iterator": - let t = skipTypes(t1, abstractRange) - result = newIntNode(nkIntLit, ord(t.kind == tyProc and - t.callConv == ccClosure and - tfIterator in t.flags)) - else: - let t2 = n[2].typ - var match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) - else: sameType(t1, t2) - result = newIntNode(nkIntLit, ord(match)) - - result.typ = n.typ - proc expectString(n: PNode) = if n.kind notin nkStrKinds: GlobalError(n.info, errStringLiteralExpected) @@ -1038,7 +1012,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = result = evalTypeTrait(n[0], operand, c.module) of mIs: n.sons[1] = evalAux(c, n.sons[1], {}) - result = evalIsOp(n) + result = c.handleIsOperator(n) of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module) of mStaticExec: let cmd = evalAux(c, n.sons[1], {}) @@ -1466,8 +1440,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode = else: stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n)) -proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode = - var p = newEvalContext(module, mode) +proc evalConstExprAux*(p: PEvalContext, module, prc: PSym, e: PNode): PNode = var s = newStackFrame() s.call = e s.prc = prc @@ -1476,12 +1449,6 @@ proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode = if result != nil and result.kind == nkExceptBranch: result = nil popStackFrame(p) -proc evalConstExpr*(module: PSym, e: PNode): PNode = - result = evalConstExprAux(module, nil, e, emConst) - -proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode = - result = evalConstExprAux(module, prc, e, emStatic) - proc setupMacroParam(x: PNode): PNode = result = x if result.kind == nkHiddenStdConv: result = result.sons[1] diff --git a/compiler/idents.nim b/compiler/idents.nim index a50c5269c..f0935c204 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -103,4 +103,5 @@ proc IdentEq*(id: PIdent, name: string): bool = result = id.id == getIdent(name).id var idAnon* = getIdent":anonymous" +let idDelegator* = getIdent":delegator" diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 6a104d139..82bfa0ad4 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -41,7 +41,7 @@ type tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface, tkIs, tkIsnot, tkIterator, tkLambda, tkLet, - tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, + tkMacro, tkMethod, tkMixin, tkUsing, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShared, tkShl, tkShr, tkStatic, tkTemplate, @@ -75,7 +75,7 @@ const "finally", "for", "from", "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", "lambda", "let", - "macro", "method", "mixin", "mod", + "macro", "method", "mixin", "using", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", "ptr", "raise", "ref", "return", "shared", "shl", "shr", "static", diff --git a/compiler/msgs.nim b/compiler/msgs.nim index dd7bad943..5363442b4 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -92,6 +92,7 @@ type errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely, + errOnlyACallOpCanBeDelegator, errUsingNoSymbol, errXExpectsTwoArguments, errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, @@ -319,6 +320,8 @@ const errCannotRenderX: "cannot render reStructuredText element \'$1\'", errVarVarTypeNotAllowed: "type \'var var\' is not allowed", errInstantiateXExplicitely: "instantiate '$1' explicitely", + errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", + errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errXExpectsTwoArguments: "\'$1\' expects two arguments", errXExpectsObjectTypes: "\'$1\' expects object types", errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", diff --git a/compiler/parser.nim b/compiler/parser.nim index bbacde1bf..0d9d27e02 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -927,9 +927,10 @@ proc parseExpr(p: var TParser): PNode = of tkTry: result = parseTry(p) else: result = simpleExpr(p) +proc parseEnum(p: var TParser): PNode proc parseObject(p: var TParser): PNode proc parseDistinct(p: var TParser): PNode -proc parseEnum(p: var TParser): PNode +proc parseTypeClass(p: var TParser): PNode proc primary(p: var TParser, mode: TPrimaryMode): PNode = #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple' @@ -959,6 +960,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode) of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode) of tkShared: result = parseTypeDescKAux(p, nkSharedTy, mode) + of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode) of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode) of tkTuple: result = parseTuple(p, mode == pmTypeDef) of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}) @@ -983,12 +985,11 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode = else: result = newNodeP(nkObjectTy, p) getTok(p) - of tkDistinct: + of tkGeneric: if mode == pmTypeDef: - result = parseDistinct(p) + result = parseTypeClass(p) else: - result = newNodeP(nkDistinctTy, p) - getTok(p) + parMessage(p, errInvalidToken, p.tok) of tkAddr: result = newNodeP(nkAddr, p) getTokNoInd(p) @@ -1612,6 +1613,32 @@ proc parseObject(p: var TParser): PNode = return addSon(result, parseObjectPart(p)) +proc parseTypeClass(p: var TParser): PNode = + result = newNodeP(nkTypeClassTy, p) + getTok(p) + addSon(result, p.parseSymbol) + if p.tok.tokType == tkCurlyDotLe and p.validInd: + addSon(result, parsePragma(p)) + else: + addSon(result, ast.emptyNode) + if p.tok.tokType == tkOf and p.tok.indent < 0: + var a = newNodeP(nkOfInherit, p) + getTok(p) + while true: + addSon(a, parseTypeDesc(p)) + if p.tok.tokType != tkComma: break + getTok(p) + addSon(result, a) + else: + addSon(result, ast.emptyNode) + if p.tok.tokType == tkComment: + skipComment(p, result) + # an initial IND{>} HAS to follow: + if not realInd(p): + addSon(result, emptyNode) + else: + addSon(result, parseStmt(p)) + proc parseDistinct(p: var TParser): PNode = #| distinct = 'distinct' optInd typeDesc result = newNodeP(nkDistinctTy, p) @@ -1747,6 +1774,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = of tkVar: result = parseSection(p, nkVarSection, parseVariable) of tkBind: result = parseBind(p, nkBindStmt) of tkMixin: result = parseBind(p, nkMixinStmt) + of tkUsing: result = parseBind(p, nkUsingStmt) else: result = simpleStmt(p) proc parseStmt(p: var TParser): PNode = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index f185d0f80..aeffcdc4c 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -24,13 +24,14 @@ const wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, - wGenSym, wInject, wRaises, wTags, wOperator} + wGenSym, wInject, wRaises, wTags, wOperator, wDelegator} converterPragmas* = procPragmas methodPragmas* = procPragmas - templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty} + templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty, + wDelegator} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, - wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject} + wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wDelegator} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises, diff --git a/compiler/sem.nim b/compiler/sem.nim index 4396a9093..71951dd3f 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -132,14 +132,42 @@ proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} = LocalError(typ.n.info, errXisNoType, typeToString(typ)) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym - proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode - -proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, - semCheck: bool = true): PNode 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 semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, + semCheck: bool = true): PNode + +proc symFromType(t: PType, info: TLineInfo): PSym = + if t.sym != nil: return t.sym + result = newSym(skType, getIdent"AnonType", t.owner, info) + result.flags.incl sfAnon + result.typ = t + +proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = + result = newSymNode(symFromType(t, info), info) + result.typ = makeTypeDesc(c, t) + +proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext = + result = newEvalContext(c.module, mode) + result.getType = proc (n: PNode): PNode = + var e = tryExpr(c, n) + if e == nil: + result = symNodeFromType(c, errorType(c), n.info) + elif e.typ == nil: + result = newSymNode(getSysSym"void") + else: + result = symNodeFromType(c, e.typ, n.info) + + result.handleIsOperator = proc (n: PNode): PNode = + result = IsOpImpl(c, n) + +proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode = + result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e) + +proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode = + result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e) proc semConstExpr(c: PContext, n: PNode): PNode = var e = semExprWithType(c, n) @@ -148,7 +176,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode = return n result = getConstExpr(c.module, e) if result == nil: - result = evalConstExpr(c.module, e) + result = evalConstExpr(c, c.module, e) if result == nil or result.kind == nkEmpty: if e.info != n.info: pushInfoContext(n.info) @@ -161,16 +189,6 @@ proc semConstExpr(c: PContext, n: PNode): PNode = include hlo, seminst, semcall -proc symFromType(t: PType, info: TLineInfo): PSym = - if t.sym != nil: return t.sym - result = newSym(skType, getIdent"AnonType", t.owner, info) - result.flags.incl sfAnon - result.typ = t - -proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode = - result = newSymNode(symFromType(t, info), info) - result.typ = makeTypeDesc(c, t) - proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = inc(evalTemplateCounter) if evalTemplateCounter > 100: @@ -205,15 +223,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, GlobalError(n.info, errRecursiveDependencyX, sym.name.s) if c.evalContext == nil: - c.evalContext = newEvalContext(c.module, emStatic) - c.evalContext.getType = proc (n: PNode): PNode = - var e = tryExpr(c, n) - if e == nil: - result = symNodeFromType(c, errorType(c), n.info) - elif e.typ == nil: - result = newSymNode(getSysSym"void") - else: - result = symNodeFromType(c, e.typ, n.info) + c.evalContext = c.createEvalContext(emStatic) result = evalMacroCall(c.evalContext, n, nOrig, sym) if semCheck: result = semAfterMacroCall(c, result, sym) @@ -250,6 +260,7 @@ proc myOpen(module: PSym): PPassContext = if c.p != nil: InternalError(module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr + c.semTryExpr = tryExpr c.semOperand = semOperand c.semConstBoolExpr = semConstBoolExpr c.semOverloadedCall = semOverloadedCall diff --git a/compiler/semcall.nim b/compiler/semcall.nim index a29efcd8a..c8f150922 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -34,36 +34,35 @@ proc sameMethodDispatcher(a, b: PSym): bool = proc determineType(c: PContext, s: PSym) -proc resolveOverloads(c: PContext, n, orig: PNode, - filter: TSymKinds): TCandidate = - var initialBinding: PNode - var f = n.sons[0] - if f.kind == nkBracketExpr: - # fill in the bindings: - initialBinding = f - f = f.sons[0] - else: - initialBinding = nil - - var - o: TOverloadIter - alt, z: TCandidate - - template best: expr = result - #Message(n.info, warnUser, renderTree(n)) - var sym = initOverloadIter(o, c, f) +proc + pickBestCandidate(c: PContext, headSymbol: PNode, + n, orig: PNode, + initialBinding: PNode, + filter: TSymKinds, + best, alt: var TCandidate, + errors: var seq[string]) = + var o: TOverloadIter + var sym = initOverloadIter(o, c, headSymbol) var symScope = o.lastOverloadScope + + var z: TCandidate if sym == nil: return initCandidate(best, sym, initialBinding, symScope) initCandidate(alt, sym, initialBinding, symScope) - + best.state = csNoMatch + while sym != nil: if sym.kind in filter: determineType(c, sym) initCandidate(z, sym, initialBinding, o.lastOverloadScope) z.calleeSym = sym matches(c, n, orig, z) + if errors != nil: + errors.safeAdd(getProcHeader(sym)) + if z.errors != nil: + for err in z.errors: + errors[errors.len - 1].add("\n " & err) if z.state == csMatch: # little hack so that iterators are preferred over everything else: if sym.kind == skIterator: inc(z.exactMatches, 200) @@ -74,17 +73,100 @@ proc resolveOverloads(c: PContext, n, orig: PNode, 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 else: nil - sym = nextOverloadIter(o, c, f) - - if best.state == csEmpty: - # no overloaded proc found - # do not generate an error yet; the semantic checking will check for - # an overloaded () operator - elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and - not sameMethodDispatcher(best.calleeSym, alt.calleeSym): - if best.state != csMatch: - InternalError(n.info, "x.state is not csMatch") - #writeMatches(best) + sym = nextOverloadIter(o, c, headSymbol) + +proc NotFoundError*(c: PContext, n: PNode, errors: seq[string]) = + # 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.InCompilesContext > 0: + # fail fast: + GlobalError(n.info, errTypeMismatch, "") + var result = msgKindToString(errTypeMismatch) + add(result, describeArgs(c, n, 1 + ord(nfDelegate in n.flags))) + add(result, ')') + + var candidates = "" + for err in errors: + add(candidates, err) + add(candidates, "\n") + + if candidates != "": + add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) + + LocalError(n.Info, errGenerated, result) + +proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) = + for scope in walkScopes(c.currentScope): + if scope.usingSyms != nil: + for s in scope.usingSyms: usedSyms.safeAdd(s) + +proc resolveOverloads(c: PContext, n, orig: PNode, + filter: TSymKinds): TCandidate = + var initialBinding: PNode + var alt: TCandidate + var f = n.sons[0] + if f.kind == nkBracketExpr: + # fill in the bindings: + initialBinding = f + f = f.sons[0] + else: + initialBinding = nil + + var errors: seq[string] + var usedSyms: seq[PNode] + + template pickBest(headSymbol: expr) = + pickBestCandidate(c, headSymbol, n, orig, initialBinding, + filter, result, alt, errors) + + gatherUsedSyms(c, usedSyms) + if usedSyms != nil: + var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms) + else: usedSyms[0] + + n.sons.insert(hiddenArg, 1) + orig.sons.insert(hiddenArg, 1) + + pickBest(f) + + if result.state != csMatch: + n.sons.delete(1) + orig.sons.delete(1) + else: return + + pickBest(f) + + let overloadsState = result.state + if overloadsState != csMatch: + if nfDelegate in n.flags: + InternalAssert f.kind == nkIdent + let calleeName = newStrNode(nkStrLit, f.ident.s) + calleeName.info = n.info + + let callOp = newIdentNode(idDelegator, n.info) + n.sons[0..0] = [callOp, calleeName] + orig.sons[0..0] = [callOp, calleeName] + + pickBest(callOp) + + if overloadsState == csEmpty and result.state == csEmpty: + LocalError(n.info, errUndeclaredIdentifier, considerAcc(f).s) + return + elif result.state != csMatch: + if nfExprCall in n.flags: + LocalError(n.info, errExprXCannotBeCalled, + renderTree(n, {renderNoComments})) + else: + 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.inCompilesContext > 0: # quick error message for performance of 'compiles' built-in: @@ -98,7 +180,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, add(args, ")") LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ - getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym), + getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym), args]) @@ -155,6 +237,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, filter: TSymKinds): PNode = var r = resolveOverloads(c, n, nOrig, filter) if r.state == csMatch: result = semResolvedCall(c, n, r) + # else: result = errorNode(c, n) proc explicitGenericInstError(n: PNode): PNode = LocalError(n.info, errCannotInstantiateX, renderTree(n)) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8b04f4af5..4c066f5fa 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -72,6 +72,7 @@ type libs*: TLinkedList # 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.} 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, @@ -204,6 +205,11 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = result = newTypeS(tyTypeDesc, c) result.addSonSkipIntLit(typ.AssertNotNil) +proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = + let typedesc = makeTypeDesc(c, typ) + let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc) + return newSymNode(sym, info) + proc newTypeS(kind: TTypeKind, c: PContext): PType = result = newType(kind, getCurrOwner()) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d00490d2a..2681150e0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -248,7 +248,11 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: # do not skip the range! n.typ = n.sons[1].typ.skipTypes(abstractVar) - else: LocalError(n.info, errInvalidArgForX, opToStr[m]) + of tyGenericParam: + # leave it for now, it will be resolved in semtypinst + n.typ = getSysType(tyInt) + else: + LocalError(n.info, errInvalidArgForX, opToStr[m]) result = n proc semSizeof(c: PContext, n: PNode): PNode = @@ -295,6 +299,39 @@ proc semOf(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) result = n +proc IsOpImpl(c: PContext, n: PNode): PNode = + InternalAssert n.sonsLen == 3 and + n[1].kind == nkSym and n[1].sym.kind == skType and + n[2].kind in {nkStrLit..nkTripleStrLit, nkType} + + let t1 = n[1].sym.typ.skipTypes({tyTypeDesc}) + + if n[2].kind in {nkStrLit..nkTripleStrLit}: + case n[2].strVal.normalize + of "closure": + let t = skipTypes(t1, abstractRange) + result = newIntNode(nkIntLit, ord(t.kind == tyProc and + t.callConv == ccClosure and + tfIterator notin t.flags)) + of "iterator": + let t = skipTypes(t1, abstractRange) + result = newIntNode(nkIntLit, ord(t.kind == tyProc and + t.callConv == ccClosure and + tfIterator in t.flags)) + else: + var match: bool + let t2 = n[2].typ + if t2.kind == tyTypeClass: + var m: TCandidate + InitCandidate(m, t2) + match = matchUserTypeClass(c, m, emptyNode, t2, t1) != nil + else: + match = sameType(t1, t2) + + result = newIntNode(nkIntLit, ord(match)) + + result.typ = n.typ + proc semIs(c: PContext, n: PNode): PNode = if sonsLen(n) != 3: LocalError(n.info, errXExpectsTwoArguments, "is") @@ -303,21 +340,21 @@ proc semIs(c: PContext, n: PNode): PNode = n.typ = getSysType(tyBool) n.sons[1] = semExprWithType(c, n[1], {efDetermineType}) - if n[1].typ.kind != tyTypeDesc: - LocalError(n[0].info, errTypeExpected) - + if n[2].kind notin {nkStrLit..nkTripleStrLit}: let t2 = semTypeNode(c, n[2], nil) n.sons[2] = newNodeIT(nkType, n[2].info, t2) - if n[1].typ.sonsLen == 0: + if n[1].typ.kind != tyTypeDesc: + n.sons[1] = makeTypeSymNode(c, n[1].typ, n[1].info) + elif n[1].typ.sonsLen == 0: # this is a typedesc variable, leave for evals return - else: - let t1 = n[1].typ.sons[0] - # BUGFIX: don't evaluate this too early: ``T is void`` - if not containsGenericType(t1): result = evalIsOp(n) - + + let t1 = n[1].typ.sons[0] + # BUGFIX: don't evaluate this too early: ``T is void`` + if not containsGenericType(t1): result = IsOpImpl(c, n) + proc semOpAux(c: PContext, n: PNode) = const flags = {efDetermineType} for i in countup(1, n.sonsLen-1): @@ -594,18 +631,18 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, call, c.p.owner) + result = evalStaticExpr(c, c.module, call, c.p.owner) if result.isNil: LocalError(n.info, errCannotInterpretNodeX, renderTree(call)) else: - result = evalConstExpr(c.module, call) + result = evalConstExpr(c, c.module, call) if result.isNil: result = n #if result != n: # echo "SUCCESS evaluated at compile time: ", call.renderTree proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) - result = evalStaticExpr(c.module, a, c.p.owner) + result = evalStaticExpr(c, c.module, a, c.p.owner) if result.isNil: LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode @@ -649,7 +686,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = n.sons[0] result.kind = nkCall for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i]) - return semExpr(c, result, flags) + return semDirectOp(c, result, flags) else: n.sons[0] = semExpr(c, n.sons[0]) let nOrig = n.copyTree @@ -699,14 +736,13 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # Now that nkSym does not imply an iteration over the proc/iterator space, # the old ``prc`` (which is likely an nkIdent) has to be restored: if result == nil: + # XXX: hmm, what kind of symbols will end up here? + # do we really need to try the overload resolution? n.sons[0] = prc nOrig.sons[0] = prc + n.flags.incl nfExprCall result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) - if result == nil: - if c.inCompilesContext > 0 or gErrorCounter == 0: - LocalError(n.info, errExprXCannotBeCalled, - renderTree(n, {renderNoComments})) - return errorNode(c, n) + if result == nil: return errorNode(c, n) #result = afterCallActions(c, result, nOrig, flags) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) @@ -734,12 +770,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = let nOrig = n.copyTree #semLazyOpAux(c, n) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) - if result == nil: - result = overloadedCallOpr(c, n) - if result == nil: - NotFoundError(c, n) - return errorNode(c, n) - result = afterCallActions(c, result, nOrig, flags) + if result != nil: result = afterCallActions(c, result, nOrig, flags) proc buildStringify(c: PContext, arg: PNode): PNode = if arg.typ != nil and @@ -946,20 +977,11 @@ proc dotTransformation(c: PContext, n: PNode): PNode = addSon(result, copyTree(n[0])) else: var i = considerAcc(n.sons[1]) - var f = searchInScopes(c, i) - # if f != nil and f.kind == skStub: loadStub(f) - # ``loadStub`` is not correct here as we don't care for ``f`` really - if f != nil: - # BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here - # This special node kind is to merge with the call handler in `semExpr`. - result = newNodeI(nkDotCall, n.info) - addSon(result, newIdentNode(i, n[1].info)) - addSon(result, copyTree(n[0])) - else: - if not ContainsOrIncl(c.UnknownIdents, i.id): - LocalError(n.Info, errUndeclaredFieldX, i.s) - result = errorNode(c, n) - + result = newNodeI(nkDotCall, n.info) + result.flags.incl nfDelegate + addSon(result, newIdentNode(i, n[1].info)) + addSon(result, copyTree(n[0])) + proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # this is difficult, because the '.' is used in many different contexts # in Nimrod. We first allow types in the semantic checking. @@ -1307,6 +1329,22 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo, result = newSym(kind, idAnon, owner, info) result.flags = {sfGenSym} +proc semUsing(c: PContext, n: PNode): PNode = + result = newNodeI(nkEmpty, n.info) + for e in n.sons: + let usedSym = semExpr(c, e) + if usedSym.kind == nkSym: + case usedSym.sym.kind + of skLocalVars + {skConst}: + c.currentScope.usingSyms.safeAdd(usedSym) + continue + of skProcKinds: + addDeclAt(c.currentScope, usedSym.sym) + continue + else: nil + + LocalError(e.info, errUsingNoSymbol, e.renderTree) + proc semExpandToAst(c: PContext, n: PNode): PNode = var macroCall = n[1] var expandedSym = expectMacroOrTemplateCall(c, macroCall) @@ -1834,7 +1872,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) - var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) + let mode = if nfDelegate in n.flags: {} else: {checkUndeclared} + var s = qualifiedLookup(c, n.sons[0], mode) if s != nil: case s.kind of skMacro: @@ -1868,6 +1907,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = elif isSymChoice(n.sons[0]) or n[0].kind == nkBracketExpr and isSymChoice(n[0][0]): result = semDirectOp(c, n, flags) + elif nfDelegate in n.flags: + result = semDirectOp(c, n, flags) else: result = semIndirectOp(c, n, flags) of nkWhen: @@ -1943,6 +1984,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkForStmt, nkParForStmt: result = semFor(c, n) of nkCaseStmt: result = semCase(c, n) of nkReturnStmt: result = semReturn(c, n) + of nkUsingStmt: result = semUsing(c, n) of nkAsmStmt: result = semAsm(c, n) of nkYieldStmt: result = semYield(c, n) of nkPragma: pragma(c, c.p.owner, n, stmtPragmas) @@ -1974,4 +2016,4 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = else: LocalError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) - incl(result.flags, nfSem) + if result != nil: incl(result.flags, nfSem) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index b9ef8b008..88567b10a 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -113,6 +113,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result.typ = getSysType(tyString) of mInstantiationInfo: result = semInstantiationInfo(c, n) of mOrd: result = semOrd(c, n) + of mHigh: result = semLowHigh(c, n, mHigh) of mShallowCopy: result = semShallowCopy(c, n, flags) of mNBindSym: result = semBindSym(c, n) of mLocals: result = semLocals(c, n) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 7e69dbd92..0ce58ba5c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -838,7 +838,14 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode = var it = n.sons[i] var key = if it.kind == nkExprColonExpr: it.sons[0] else: it let m = lookupMacro(c, key) - if m == nil: continue + if m == nil: + if key.kind == nkIdent and key.ident.id == ord(wDelegator): + if considerAcc(prc.sons[namePos]).s == "()": + prc.sons[namePos] = newIdentNode(idDelegator, prc.info) + prc.sons[pragmasPos] = copyExcept(n, i) + else: + LocalError(prc.info, errOnlyACallOpCanBeDelegator) + continue # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and # let the semantic checker deal with it: var x = newNodeI(nkCall, n.info) @@ -1147,7 +1154,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = proc semStaticStmt(c: PContext, n: PNode): PNode = let a = semStmt(c, n.sons[0]) - result = evalStaticExpr(c.module, a, c.p.owner) + result = evalStaticExpr(c, c.module, a, c.p.owner) if result.isNil: LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) result = emptyNode diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 14f96497d..64140274e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -608,7 +608,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if genericParams.sons[i].sym.name.id == finalTypId.id: return genericParams.sons[i].typ - var s = newSym(skType, finalTypId, getCurrOwner(), info) + var s = newSym(skType, finalTypId, typeClass.sym, info) if typId == nil: s.flags.incl(sfAnon) s.linkTo(typeClass) s.position = genericParams.len @@ -871,6 +871,21 @@ proc freshType(res, prev: PType): PType {.inline.} = else: result = res +proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = + # if n.sonsLen == 0: return newConstraint(c, tyTypeClass) + result = newOrPrevType(tyTypeClass, prev, c) + result.testeeName = considerAcc(n[0]) + result.n = n[3] + + let + pragmas = n[1] + inherited = n[2] + + if inherited.kind != nkEmpty: + for n in inherited.sons: + let typ = semTypeNode(c, n, nil) + result.sons.safeAdd(typ) + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil if gCmd == cmdIdeTools: suggestExpr(c, n) @@ -973,6 +988,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev) + of nkTypeClassTy: result = semTypeClass(c, n, prev) of nkRefTy: result = semAnyRef(c, n, tyRef, prev) of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev) of nkVarTy: result = semVarType(c, n, prev) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 0c15c7248..b638449d2 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -148,12 +148,13 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = if result != nil: return for i in countup(1, sonsLen(t) - 1): var x = t.sons[i] - if x.kind == tyGenericParam: + if x.kind == tyGenericParam: x = lookupTypeVar(cl, x) if header == nil: header = copyType(t, t.owner, false) header.sons[i] = x propagateToOwner(header, x) - #idTablePut(cl.typeMap, body.sons[i-1], x) + #idTablePut(cl.typeMap, body.sons[i-1], x) + if header != nil: # search again after first pass: result = searchInstTypes(header) @@ -200,6 +201,9 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = result = lookupTypeVar(cl, t) if result.kind == tyGenericInvokation: result = handleGenericInvokation(cl, result) + of tyExpr: + if t.sym != nil and t.sym.kind == skGenericParam: + result = lookupTypeVar(cl, t) of tyGenericInvokation: result = handleGenericInvokation(cl, t) of tyGenericBody: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b331a08e5..318acc660 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -40,7 +40,9 @@ type # be instantiated typedescMatched: bool inheritancePenalty: int # to prefer closest father object type - + errors*: seq[string] # additional clarifications to be displayed to the + # user if overload resolution fails + TTypeRelation* = enum # order is important! isNone, isConvertible, isIntConv, @@ -200,28 +202,6 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string = add(result, argTypeToString(arg)) if i != sonsLen(n) - 1: add(result, ", ") -proc NotFoundError*(c: PContext, n: PNode) = - # 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.InCompilesContext > 0: - # fail fast: - GlobalError(n.info, errTypeMismatch, "") - var result = msgKindToString(errTypeMismatch) - add(result, describeArgs(c, n)) - add(result, ')') - var candidates = "" - var o: TOverloadIter - var sym = initOverloadIter(o, c, n.sons[0]) - while sym != nil: - if sym.kind in RoutineKinds: - add(candidates, getProcHeader(sym)) - add(candidates, "\n") - sym = nextOverloadIter(o, c, n.sons[0]) - if candidates != "": - add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) - LocalError(n.Info, errGenerated, result) - proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation proc concreteType(c: TCandidate, t: PType): PType = case t.kind @@ -643,7 +623,10 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = else: result = isNone else: - result = matchTypeClass(c, f, a) + if a.kind == tyTypeClass: + result = isGeneric + else: + result = matchTypeClass(c, f, a) if result == isGeneric: var concrete = concreteType(c, a) @@ -754,35 +737,93 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true +proc matchUserTypeClass*(c: PContext, m: var TCandidate, + arg: PNode, f, a: PType): PNode = + if f.n == nil: + let r = typeRel(m, f, a) + return if r == isGeneric: arg else: nil + + var prev = PType(idTableGet(m.bindings, f)) + if prev != nil: + if sameType(prev, a): return arg + else: return nil + + # pushInfoContext(arg.info) + openScope(c) + + var testee = newSym(skParam, f.testeeName, f.sym, f.sym.info) + testee.typ = a + addDecl(c, testee) + + for stmt in f.n: + var e = c.semTryExpr(c, copyTree(stmt)) + if e == nil: + let expStr = renderTree(stmt, {renderNoComments}) + m.errors.safeAdd("can't compile " & expStr & " for " & a.typeToString) + return nil + case e.kind + of nkReturnStmt: + nil + of nkTypeSection: nil + of nkConstDef: nil + else: + if e.typ.kind == tyBool: + let verdict = c.semConstExpr(c, e) + if verdict.intVal == 0: + let expStr = renderTree(stmt, {renderNoComments}) + m.errors.safeAdd(expStr & " doesn't hold for " & a.typeToString) + return nil + + closeScope(c) + + result = arg + put(m.bindings, f, a) + proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, - arg, argOrig: PNode): PNode = + argSemantized, argOrig: PNode): PNode = + var arg = argSemantized var r: TTypeRelation let fMaybeExpr = f.skipTypes({tyDistinct}) - if fMaybeExpr.kind == tyExpr: + case fMaybeExpr.kind + of tyExpr: if fMaybeExpr.sonsLen == 0: r = isGeneric else: - let match = matchTypeClass(m, fMaybeExpr, a) - if match != isGeneric: r = isNone + if a.kind == tyExpr: + InternalAssert a.len > 0 + r = typeRel(m, f.lastSon, a.lastSon) else: - # XXX: Ideally, this should happen much earlier somewhere near - # semOpAux, but to do that, we need to be able to query the - # overload set to determine whether compile-time value is expected - # for the param before entering the full-blown sigmatch algorithm. - # This is related to the immediate pragma since querying the - # overload set could help there too. - var evaluated = c.semConstExpr(c, arg) - if evaluated != nil: - r = isGeneric - arg.typ = newTypeS(tyExpr, c) - arg.typ.sons = @[evaluated.typ] - arg.typ.n = evaluated + let match = matchTypeClass(m, fMaybeExpr, a) + if match != isGeneric: r = isNone + else: + # XXX: Ideally, this should happen much earlier somewhere near + # semOpAux, but to do that, we need to be able to query the + # overload set to determine whether compile-time value is expected + # for the param before entering the full-blown sigmatch algorithm. + # This is related to the immediate pragma since querying the + # overload set could help there too. + var evaluated = c.semConstExpr(c, arg) + if evaluated != nil: + r = isGeneric + arg.typ = newTypeS(tyExpr, c) + arg.typ.sons = @[evaluated.typ] + arg.typ.n = evaluated if r == isGeneric: put(m.bindings, f, arg.typ) + of tyTypeClass: + if fMaybeExpr.n != nil: + let match = matchUserTypeClass(c, m, arg, fMaybeExpr, a) + if match != nil: + r = isGeneric + arg = match + else: + r = isNone + else: + r = typeRel(m, f, a) else: r = typeRel(m, f, a) - + case r of isConvertible: inc(m.convMatches) diff --git a/compiler/types.nim b/compiler/types.nim index 084091630..f9c40e201 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -445,6 +445,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if t.len == 0: result = "typedesc" else: result = "typedesc[" & constraintsToStr(t) & "]" of tyTypeClass: + if t.n != nil: return t.sym.owner.name.s case t.len of 0: result = "typeclass[]" of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]" diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index a9540269c..b37a7bb4f 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -28,7 +28,7 @@ type wElif, wElse, wEnd, wEnum, wExcept, wExport, wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn, wInclude, wInterface, wIs, wIsnot, wIterator, wLambda, wLet, - wMacro, wMethod, wMixin, wMod, wNil, + wMacro, wMethod, wMixin, wUsing, wMod, wNil, wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, wShared, wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wVar, wWhen, wWhile, wWith, wWithout, wXor, wYield, @@ -39,7 +39,8 @@ type wDestroy, - wImmediate, wDestructor, wImportCpp, wImportObjC, + wImmediate, wDestructor, wDelegator, + wImportCpp, wImportObjC, wImportCompilerProc, wImportc, wExportc, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, @@ -71,7 +72,7 @@ type wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch, wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename, - wUnion, wUnsigned, wUsing, wVirtual, wVoid, wVolatile, wWchar_t, + wUnion, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t, wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept, wThread_local, wStatic_assert, wChar16_t, wChar32_t, @@ -94,7 +95,7 @@ const cppNimSharedKeywords* = { wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, - wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile} + wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing } specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", @@ -106,7 +107,7 @@ const "finally", "for", "from", "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", "lambda", "let", - "macro", "method", "mixin", "mod", "nil", "not", "notin", + "macro", "method", "mixin", "using", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", "ptr", "raise", "ref", "return", "shared", "shl", "shr", "static", @@ -120,7 +121,8 @@ const "destroy", - "immediate", "destructor", "importcpp", "importobjc", + "immediate", "destructor", "delegator", + "importcpp", "importobjc", "importcompilerproc", "importc", "exportc", "incompletestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", @@ -152,7 +154,7 @@ const "private", "protected", "public", "register", "reinterpret_cast", "short", "signed", "sizeof", "static_cast", "struct", "switch", "this", "throw", "true", "typedef", "typeid", - "typename", "union", "unsigned", "using", "virtual", "void", "volatile", + "typename", "union", "unsigned", "virtual", "void", "volatile", "wchar_t", "alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept", |