diff options
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/idents.nim | 1 | ||||
-rw-r--r-- | compiler/msgs.nim | 2 | ||||
-rw-r--r-- | compiler/pragmas.nim | 7 | ||||
-rw-r--r-- | compiler/semcall.nim | 113 | ||||
-rw-r--r-- | compiler/semexprs.nim | 31 | ||||
-rw-r--r-- | compiler/semmagic.nim | 1 | ||||
-rw-r--r-- | compiler/semstmts.nim | 9 | ||||
-rw-r--r-- | compiler/semtypes.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 22 | ||||
-rw-r--r-- | compiler/types.nim | 1 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 6 | ||||
-rw-r--r-- | tests/reject/topaque.nim | 24 |
13 files changed, 131 insertions, 94 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 04ac88c1c..b12d58626 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -216,7 +216,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 @@ -353,6 +353,7 @@ type # efficiency nfTransf, # node has been transformed nfSem # node has been checked for semantics + nfDelegate # the call can use a delegator TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 23) @@ -774,7 +775,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 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/msgs.nim b/compiler/msgs.nim index 3e5304358..47a4d284b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -89,6 +89,7 @@ type errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely, + errOnlyACallOpCanBeDelegator, errXExpectsTwoArguments, errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, @@ -316,6 +317,7 @@ 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", errXExpectsTwoArguments: "\'$1\' expects two arguments", errXExpectsObjectTypes: "\'$1\' expects object types", errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 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/semcall.nim b/compiler/semcall.nim index 735e6fac8..22ee8c099 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -34,25 +34,18 @@ 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) @@ -64,6 +57,11 @@ proc resolveOverloads(c: PContext, n, orig: PNode, 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 +72,71 @@ 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 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] + + template pickBest(headSymbol: expr) = + pickBestCandidate(c, headSymbol, n, orig, initialBinding, + filter, result, alt, errors) + + pickBest(f) + + if result.state == csEmpty: + 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 result.state == csEmpty: + 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 +150,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 +207,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/semexprs.nim b/compiler/semexprs.nim index d0b81364e..369b0eb90 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -682,7 +682,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 @@ -767,11 +767,6 @@ 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) proc buildStringify(c: PContext, arg: PNode): PNode = @@ -979,20 +974,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. @@ -1866,7 +1852,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: @@ -1900,6 +1887,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: 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 3b83290ea..022d412ce 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -835,7 +835,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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e9541997f..d8846d717 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 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 25d0d8004..5411904df 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -202,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 diff --git a/compiler/types.nim b/compiler/types.nim index 2564741d8..99bedfca7 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -442,6 +442,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..f8a19ae19 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -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, @@ -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", diff --git a/tests/reject/topaque.nim b/tests/reject/topaque.nim index ac390835b..f0587c959 100644 --- a/tests/reject/topaque.nim +++ b/tests/reject/topaque.nim @@ -1,18 +1,18 @@ discard """ file: "topaque.nim" line: 16 - errormsg: "undeclared field: \'buffer\'" + errormsg: "undeclared identifier: \'buffer\'" """ -# Test the new opaque types - -import - mopaque - -var - L: TLexer - -L.filename = "ha" -L.line = 34 -L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer' +# Test the new opaque types + +import + mopaque + +var + L: TLexer + +L.filename = "ha" +L.line = 34 +L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer' |