diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/astalgo.nim | 5 | ||||
-rw-r--r-- | compiler/canonicalizer.nim | 1 | ||||
-rw-r--r-- | compiler/lexer.nim | 3 | ||||
-rw-r--r-- | compiler/parser.nim | 19 | ||||
-rw-r--r-- | compiler/pragmas.nim | 18 | ||||
-rw-r--r-- | compiler/renderer.nim | 8 | ||||
-rw-r--r-- | compiler/semcall.nim | 42 | ||||
-rw-r--r-- | compiler/semdata.nim | 16 | ||||
-rw-r--r-- | compiler/semexprs.nim | 210 | ||||
-rw-r--r-- | compiler/seminst.nim | 44 | ||||
-rw-r--r-- | compiler/semstmts.nim | 55 | ||||
-rw-r--r-- | compiler/semtypes.nim | 36 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 13 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 4 | ||||
-rw-r--r-- | compiler/types.nim | 1 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 3 |
17 files changed, 282 insertions, 202 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 2ce0afcc3..5c2349daa 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -298,6 +298,7 @@ const sfWrittenTo* = sfBorrow # param is assigned to sfEscapes* = sfProcvar # param escapes sfBase* = sfDiscriminant + sfIsSelf* = sfOverriden # param is 'self' const # getting ready for the future expr/stmt merge @@ -458,7 +459,7 @@ type tfByCopy, # pass object/tuple by copy (C backend) tfByRef, # pass object/tuple by reference (C backend) tfIterator, # type is really an iterator, not a tyProc - tfShared, # type is 'shared' + tfPartial, # type is declared as 'partial' tfNotNil, # type cannot be 'nil' tfNeedsInit, # type constains a "not nil" constraint somewhere or some @@ -533,7 +534,7 @@ const skError* = skUnknown # type flags that are essential for type equality: - eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr} + eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr} type TMagic* = enum # symbols that require compiler magic: @@ -753,7 +754,6 @@ type TScope* = object depthLevel*: int symbols*: TStrTable - usingSyms*: seq[PNode] parent*: PScope PScope* = ref TScope diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 1a70875d4..4772009b4 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -635,7 +635,7 @@ proc reallySameIdent(a, b: string): bool {.inline.} = else: result = true -proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = +proc strTableIncl*(t: var TStrTable, n: PSym; onConflictKeepOld=false): bool {.discardable.} = # returns true if n is already in the string table: # It is essential that `n` is written nevertheless! # This way the newest redefinition is picked by the semantic analyses! @@ -654,7 +654,8 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = replaceSlot = h h = nextTry(h, high(t.data)) if replaceSlot >= 0: - t.data[replaceSlot] = n # overwrite it with newer definition! + if not onConflictKeepOld: + t.data[replaceSlot] = n # overwrite it with newer definition! return true # found it elif mustRehash(len(t.data), t.counter): strTableEnlarge(t) diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim index 9afe4ab10..85dbe7536 100644 --- a/compiler/canonicalizer.nim +++ b/compiler/canonicalizer.nim @@ -158,7 +158,6 @@ proc hashType(c: var MD5Context, t: PType) = if tfThread in t.flags: c &= ".thread" else: for i in 0.. <t.len: c.hashType(t.sons[i]) - if tfShared in t.flags: c &= "shared" if tfNotNil in t.flags: c &= "not nil" proc canonConst(n: PNode): TUid = diff --git a/compiler/lexer.nim b/compiler/lexer.nim index fc43f8d6a..69a0fea2a 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -44,7 +44,8 @@ type tkLet, tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, - tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic, + tkProc, tkPtr, tkRaise, tkRef, tkReturn, + tkShl, tkShr, tkStatic, tkTemplate, tkTry, tkTuple, tkType, tkUsing, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor, diff --git a/compiler/parser.nim b/compiler/parser.nim index c4681a5cd..f22177ac1 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -804,20 +804,24 @@ proc parsePragma(p: var TParser): PNode = else: parMessage(p, errTokenExpected, ".}") dec p.inPragma -proc identVis(p: var TParser): PNode = +proc identVis(p: var TParser; allowDot=false): PNode = #| identVis = symbol opr? # postfix position + #| identVisDot = symbol '.' optInd symbol opr? var a = parseSymbol(p) if p.tok.tokType == tkOpr: result = newNodeP(nkPostfix, p) addSon(result, newIdentNodeP(p.tok.ident, p)) addSon(result, a) getTok(p) + elif p.tok.tokType == tkDot and allowDot: + result = dotExpr(p, a) else: result = a -proc identWithPragma(p: var TParser): PNode = +proc identWithPragma(p: var TParser; allowDot=false): PNode = #| identWithPragma = identVis pragma? - var a = identVis(p) + #| identWithPragmaDot = identVisDot pragma? + var a = identVis(p, allowDot) if p.tok.tokType == tkCurlyDotLe: result = newNodeP(nkPragmaExpr, p) addSon(result, a) @@ -1803,10 +1807,11 @@ proc parseTypeClass(p: var TParser): PNode = addSon(result, parseStmt(p)) proc parseTypeDef(p: var TParser): PNode = - #| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux + #| + #| typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux #| indAndComment? result = newNodeP(nkTypeDef, p) - addSon(result, identWithPragma(p)) + addSon(result, identWithPragma(p, allowDot=true)) if p.tok.tokType == tkBracketLe and p.validInd: addSon(result, parseGenericParamList(p)) else: @@ -1903,7 +1908,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = #| | 'converter' routine #| | 'type' section(typeDef) #| | 'const' section(constant) - #| | ('let' | 'var') section(variable) + #| | ('let' | 'var' | 'using') section(variable) #| | bindStmt | mixinStmt) #| / simpleStmt case p.tok.tokType @@ -1940,7 +1945,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) + of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) else: result = simpleStmt(p) proc parseStmt(p: var TParser): PNode = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index f10d552a1..2280ef712 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -46,7 +46,7 @@ const wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, - wInjectStmt, wDeprecated, wExperimental} + wInjectStmt, wDeprecated, wExperimental, wThis} lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, @@ -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} + wBorrow, wGcSafe, wExportNims, wPartial} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wGuard, wBitsize} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, @@ -835,6 +835,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, noVal(it) if sym.kind != skType or sym.typ == nil: invalidPragma(it) else: incl(sym.typ.flags, tfByCopy) + of wPartial: + noVal(it) + if sym.kind != skType or sym.typ == nil: invalidPragma(it) + else: + incl(sym.typ.flags, tfPartial) + # .partial types can only work with dead code elimination + # to prevent the codegen from doing anything before we compiled + # the whole program: + incl gGlobalOptions, optDeadCodeElim of wInject, wGensym: # We check for errors, but do nothing with these pragmas otherwise # as they are handled directly in 'evalTemplate'. @@ -875,6 +884,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, c.module.flags.incl sfExperimental else: localError(it.info, "'experimental' pragma only valid as toplevel statement") + of wThis: + if it.kind == nkExprColonExpr: + c.selfName = considerQuotedIdent(it[1]) + else: + c.selfName = getIdent("self") of wNoRewrite: noVal(it) of wBase: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index d63cba4be..12852ba3d 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -463,6 +463,9 @@ proc lsub(n: PNode): int = of nkVarSection, nkLetSection: if sonsLen(n) > 1: result = MaxLineLen + 1 else: result = lsons(n) + len("var_") + of nkUsingStmt: + if sonsLen(n) > 1: result = MaxLineLen + 1 + else: result = lsons(n) + len("using_") of nkReturnStmt: result = lsub(n.sons[0]) + len("return_") of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_") of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_") @@ -1173,11 +1176,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = initContext(a) incl(a.flags, rfInConstExpr) gsection(g, n, a, tkConst, "const") - of nkVarSection, nkLetSection: + of nkVarSection, nkLetSection, nkUsingStmt: var L = sonsLen(n) if L == 0: return if n.kind == nkVarSection: putWithSpace(g, tkVar, "var") - else: putWithSpace(g, tkLet, "let") + elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let") + else: putWithSpace(g, tkUsing, "using") if L > 1: gcoms(g) indentNL(g) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index eba1059ef..916d897c9 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -50,7 +50,8 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, var syms: seq[tuple[a: PSym, b: int]] = @[] while symx != nil: - if symx.kind in filter: syms.add((symx, o.lastOverloadScope)) + if symx.kind in filter: + syms.add((symx, o.lastOverloadScope)) symx = nextOverloadIter(o, c, headSymbol) if syms.len == 0: return @@ -63,7 +64,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, let sym = syms[i][0] determineType(c, sym) initCandidate(c, z, sym, initialBinding, syms[i][1]) - z.calleeSym = sym #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: # gDebug = true @@ -138,11 +138,6 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = else: 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; errors: var CandidateErrors): TCandidate = @@ -156,31 +151,30 @@ proc resolveOverloads(c: PContext, n, orig: PNode, else: initialBinding = nil - var usedSyms: seq[PNode] - - template pickBest(headSymbol: expr) = + template pickBest(headSymbol) = 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 c.p != nil and c.p.selfSym != nil: + # we need to enforce semchecking of selfSym again because it + # might need auto-deref: + var hiddenArg = newSymNode(c.p.selfSym) + hiddenArg.typ = nil + 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 + if nfDotField in n.flags: internalAssert f.kind == nkIdent and n.sonsLen >= 2 let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 656bfc449..a13f2c232 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -30,6 +30,7 @@ type # statements owner*: PSym # the symbol this context belongs to resultSym*: PSym # the result symbol (if we are in a proc) + selfSym*: PSym # the 'self' symbol (if available) nestedLoopCounter*: int # whether we are in a loop or not nestedBlockCounter*: int # whether we are in a block or not inTryStmt*: int # whether we are in a try statement; works also @@ -103,7 +104,8 @@ type inParallelStmt*: int instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo; op: TTypeAttachedOp): PSym {.nimcall.} - + selfName*: PIdent + signatures*: TStrTable proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s @@ -154,16 +156,6 @@ proc popOwner() = proc lastOptionEntry(c: PContext): POptionEntry = result = POptionEntry(c.optionStack.tail) -proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = - if owner == nil: - internalError("owner is nil") - return - var x: PProcCon - new(x) - x.owner = owner - x.next = c.p - c.p = x - proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc newOptionEntry(): POptionEntry = @@ -187,6 +179,8 @@ proc newContext(module: PSym): PContext = initStrTable(result.userPragmas) result.generics = @[] result.unknownIdents = initIntSet() + initStrTable(result.signatures) + proc inclSym(sq: var TSymSeq, s: PSym) = var L = len(sq) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 87d7764a2..16b4ee479 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -77,88 +77,6 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = result.typ = s.typ result.info = n.info -proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = - case s.kind - of skConst: - markUsed(n.info, s) - styleCheckUse(n.info, s) - case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind - of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, - tyTuple, tySet, tyUInt..tyUInt64: - if s.magic == mNone: result = inlineConst(n, s) - else: result = newSymNode(s, n.info) - of tyArrayConstr, tySequence: - # Consider:: - # const x = [] - # proc p(a: openarray[int]) - # proc q(a: openarray[char]) - # p(x) - # q(x) - # - # It is clear that ``[]`` means two totally different things. Thus, we - # copy `x`'s AST into each context, so that the type fixup phase can - # deal with two different ``[]``. - if s.ast.len == 0: result = inlineConst(n, s) - else: result = newSymNode(s, n.info) - else: - result = newSymNode(s, n.info) - of skMacro: result = semMacroExpr(c, n, n, s, flags) - of skTemplate: result = semTemplateExpr(c, n, s, flags) - of skParam: - markUsed(n.info, s) - styleCheckUse(n.info, s) - if s.typ.kind == tyStatic and s.typ.n != nil: - # XXX see the hack in sigmatch.nim ... - return s.typ.n - elif sfGenSym in s.flags: - if c.p.wasForwarded: - # gensym'ed parameters that nevertheless have been forward declared - # need a special fixup: - let realParam = c.p.owner.typ.n[s.position+1] - internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam - return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) - elif c.p.owner.kind == skMacro: - # gensym'ed macro parameters need a similar hack (see bug #1944): - var u = searchInScopes(c, s.name) - internalAssert u != nil and u.kind == skParam and u.owner == s.owner - return newSymNode(u, n.info) - result = newSymNode(s, n.info) - of skVar, skLet, skResult, skForVar: - if s.magic == mNimvm: - localError(n.info, "illegal context for 'nimvm' magic") - - markUsed(n.info, s) - styleCheckUse(n.info, s) - # if a proc accesses a global variable, it is not side effect free: - if sfGlobal in s.flags: - incl(c.p.owner.flags, sfSideEffect) - result = newSymNode(s, n.info) - # We cannot check for access to outer vars for example because it's still - # not sure the symbol really ends up being used: - # var len = 0 # but won't be called - # genericThatUsesLen(x) # marked as taking a closure? - of skGenericParam: - styleCheckUse(n.info, s) - if s.typ.kind == tyStatic: - result = newSymNode(s, n.info) - result.typ = s.typ - elif s.ast != nil: - result = semExpr(c, s.ast) - else: - n.typ = s.typ - return n - of skType: - markUsed(n.info, s) - styleCheckUse(n.info, s) - if s.typ.kind == tyStatic and s.typ.n != nil: - return s.typ.n - result = newSymNode(s, n.info) - result.typ = makeTypeDesc(c, s.typ) - else: - markUsed(n.info, s) - styleCheckUse(n.info, s) - result = newSymNode(s, n.info) - type TConvStatus = enum convOK, @@ -1015,6 +933,116 @@ proc readTypeParameter(c: PContext, typ: PType, return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) #echo "came here: returned nil" +proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = + case s.kind + of skConst: + markUsed(n.info, s) + styleCheckUse(n.info, s) + case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind + of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, + tyTuple, tySet, tyUInt..tyUInt64: + if s.magic == mNone: result = inlineConst(n, s) + else: result = newSymNode(s, n.info) + of tyArrayConstr, tySequence: + # Consider:: + # const x = [] + # proc p(a: openarray[int]) + # proc q(a: openarray[char]) + # p(x) + # q(x) + # + # It is clear that ``[]`` means two totally different things. Thus, we + # copy `x`'s AST into each context, so that the type fixup phase can + # deal with two different ``[]``. + if s.ast.len == 0: result = inlineConst(n, s) + else: result = newSymNode(s, n.info) + else: + result = newSymNode(s, n.info) + of skMacro: result = semMacroExpr(c, n, n, s, flags) + of skTemplate: result = semTemplateExpr(c, n, s, flags) + of skParam: + markUsed(n.info, s) + styleCheckUse(n.info, s) + if s.typ.kind == tyStatic and s.typ.n != nil: + # XXX see the hack in sigmatch.nim ... + return s.typ.n + elif sfGenSym in s.flags: + if c.p.wasForwarded: + # gensym'ed parameters that nevertheless have been forward declared + # need a special fixup: + let realParam = c.p.owner.typ.n[s.position+1] + internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam + return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) + elif c.p.owner.kind == skMacro: + # gensym'ed macro parameters need a similar hack (see bug #1944): + var u = searchInScopes(c, s.name) + internalAssert u != nil and u.kind == skParam and u.owner == s.owner + return newSymNode(u, n.info) + result = newSymNode(s, n.info) + of skVar, skLet, skResult, skForVar: + if s.magic == mNimvm: + localError(n.info, "illegal context for 'nimvm' magic") + + markUsed(n.info, s) + styleCheckUse(n.info, s) + # if a proc accesses a global variable, it is not side effect free: + if sfGlobal in s.flags: + incl(c.p.owner.flags, sfSideEffect) + result = newSymNode(s, n.info) + # We cannot check for access to outer vars for example because it's still + # not sure the symbol really ends up being used: + # var len = 0 # but won't be called + # genericThatUsesLen(x) # marked as taking a closure? + of skGenericParam: + styleCheckUse(n.info, s) + if s.typ.kind == tyStatic: + result = newSymNode(s, n.info) + result.typ = s.typ + elif s.ast != nil: + result = semExpr(c, s.ast) + else: + n.typ = s.typ + return n + of skType: + markUsed(n.info, s) + styleCheckUse(n.info, s) + if s.typ.kind == tyStatic and s.typ.n != nil: + return s.typ.n + result = newSymNode(s, n.info) + result.typ = makeTypeDesc(c, s.typ) + of skField: + if c.p != nil and c.p.selfSym != nil: + var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef}) + while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct}) + var check: PNode = nil + if ty.kind == tyObject: + while true: + check = nil + let f = lookupInRecordAndBuildCheck(c, n, ty.n, s.name, check) + if f != nil and fieldVisible(c, f): + # is the access to a public field or in the same module or in a friend? + doAssert f == s + markUsed(n.info, f) + styleCheckUse(n.info, f) + result = newNodeIT(nkDotExpr, n.info, f.typ) + result.add makeDeref(newSymNode(c.p.selfSym)) + result.add newSymNode(f) # we now have the correct field + if check != nil: + check.sons[0] = result + check.typ = result.typ + result = check + return result + if ty.sons[0] == nil: break + ty = skipTypes(ty.sons[0], {tyGenericInst}) + # old code, not sure if it's live code: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access checkSonsLen(n, 2) @@ -1528,24 +1556,6 @@ 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) - if not experimentalMode(c): - localError(n.info, "use the {.experimental.} pragma to enable 'using'") - 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: discard - - localError(e.info, errUsingNoSymbol, e.renderTree) - proc semExpandToAst(c: PContext, n: PNode): PNode = var macroCall = n[1] var expandedSym = expectMacroOrTemplateCall(c, macroCall) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 2c767ffc6..4a45dee9d 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -10,6 +10,47 @@ # This module implements the instantiation of generic procs. # included from sem.nim +proc addObjFieldsToLocalScope(c: PContext; n: PNode) = + template rec(n) = addObjFieldsToLocalScope(c, n) + case n.kind + of nkRecList: + for i in countup(0, len(n)-1): + rec n[i] + of nkRecCase: + if n.len > 0: rec n.sons[0] + for i in countup(1, len(n)-1): + if n[i].kind in {nkOfBranch, nkElse}: rec lastSon(n[i]) + of nkSym: + let f = n.sym + if f.kind == skField and fieldVisible(c, f): + c.currentScope.symbols.strTableIncl(f, onConflictKeepOld=true) + incl(f.flags, sfUsed) + # it is not an error to shadow fields via parameters + else: discard + +proc rawPushProcCon(c: PContext, owner: PSym) = + var x: PProcCon + new(x) + x.owner = owner + x.next = c.p + c.p = x + +proc rawHandleSelf(c: PContext; owner: PSym) = + if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil: + let params = owner.typ.n + if params.len > 1: + let arg = params[1].sym + if arg.name.id == c.selfName.id: + c.p.selfSym = arg + arg.flags.incl sfIsSelf + let t = c.p.selfSym.typ.skipTypes(abstractPtrs) + if t.kind == tyObject: + addObjFieldsToLocalScope(c, t.n) + +proc pushProcCon*(c: PContext; owner: PSym) = + rawPushProcCon(c, owner) + rawHandleSelf(c, owner) + iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym = internalAssert n.kind == nkGenericParams for i, a in n.pairs: @@ -248,7 +289,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, addDecl(c, s) entry.concreteTypes[i] = s.typ inc i - pushProcCon(c, result) + rawPushProcCon(c, result) instantiateProcType(c, pt, result, info) for j in 1 .. result.typ.len-1: entry.concreteTypes[i] = result.typ.sons[j] @@ -263,6 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # a ``compiles`` context but this is the lesser evil. See # bug #1055 (tevilcompiles). #if c.compilesContextId == 0: + rawHandleSelf(c, result) entry.compilesId = c.compilesContextId fn.procInstCache.safeAdd(entry) c.generics.add(makeInstPair(fn, entry)) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index edcf079fa..5d16f2fba 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -386,6 +386,30 @@ proc isDiscardUnderscore(v: PSym): bool = v.flags.incl(sfGenSym) result = true +proc semUsing(c: PContext; n: PNode): PNode = + result = ast.emptyNode + if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using") + if not experimentalMode(c): + localError(n.info, "use the {.experimental.} pragma to enable 'using'") + for i in countup(0, sonsLen(n)-1): + var a = n.sons[i] + if gCmd == cmdIdeTools: suggestStmt(c, a) + if a.kind == nkCommentStmt: continue + if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a) + checkMinSonsLen(a, 3) + var length = sonsLen(a) + if a.sons[length-2].kind != nkEmpty: + let typ = semTypeNode(c, a.sons[length-2], nil) + for j in countup(0, length-3): + let v = semIdentDef(c, a.sons[j], skParam) + v.typ = typ + strTableIncl(c.signatures, v) + else: + localError(a.info, "'using' section must have a type") + var def: PNode + if a.sons[length-1].kind != nkEmpty: + localError(a.info, "'using' sections cannot contain assignments") + proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode result = copyNode(n) @@ -640,13 +664,20 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = if a.kind == nkCommentStmt: continue if a.kind != nkTypeDef: illFormedAst(a) checkSonsLen(a, 3) - var s = semIdentDef(c, a.sons[0], skType) - s.typ = newTypeS(tyForward, c) - s.typ.sym = s # process pragmas: - if a.sons[0].kind == nkPragmaExpr: - pragma(c, s, a.sons[0].sons[1], typePragmas) - # add it here, so that recursive types are possible: - if sfGenSym notin s.flags: addInterfaceDecl(c, s) + let name = a.sons[0] + var s: PSym + if name.kind == nkDotExpr: + s = qualifiedLookUp(c, name) + if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags: + localError(name.info, "only .partial objects can be extended") + else: + s = semIdentDef(c, name, skType) + s.typ = newTypeS(tyForward, c) + s.typ.sym = s # process pragmas: + if name.kind == nkPragmaExpr: + pragma(c, s, name.sons[1], typePragmas) + # add it here, so that recursive types are possible: + if sfGenSym notin s.flags: addInterfaceDecl(c, s) a.sons[0] = newSymNode(s) proc typeSectionRightSidePass(c: PContext, n: PNode) = @@ -655,8 +686,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a) checkSonsLen(a, 3) - if (a.sons[0].kind != nkSym): illFormedAst(a) - var s = a.sons[0].sym + let name = a.sons[0] + if (name.kind != nkSym): illFormedAst(a) + var s = name.sym if s.magic == mNone and a.sons[2].kind == nkEmpty: localError(a.info, errImplOfXexpected, s.name.s) if s.magic != mNone: processMagicType(c, s) @@ -1206,9 +1238,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # Macros and Templates can have generic parameters, but they are # only used for overload resolution (there is no instantiation of # the symbol, so we must process the body now) + pushProcCon(c, s) if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: if not usePseudoGenerics: paramsTypeCheck(c, s.typ) - pushProcCon(c, s) + c.p.wasForwarded = proto != nil maybeAddResult(c, s, n) if sfImportc notin s.flags: @@ -1217,7 +1250,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # unfortunately we cannot skip this step when in 'system.compiles' # context as it may even be evaluated in 'system.compiles': n.sons[bodyPos] = transformBody(c.module, semBody, s) - popProcCon(c) else: if s.typ.sons[0] != nil and kind != skIterator: addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) @@ -1228,6 +1260,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfImportc in s.flags: # so we just ignore the body after semantic checking for importc: n.sons[bodyPos] = ast.emptyNode + popProcCon(c) else: if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s) if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index ac425ba15..62d02fe10 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -673,7 +673,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = if n.kind != nkObjectTy: internalError(n.info, "semObjectNode") result = newOrPrevType(tyObject, prev, c) rawAddSon(result, base) - result.n = newNodeI(nkRecList, n.info) + if result.n.isNil: + result.n = newNodeI(nkRecList, n.info) + else: + # partial object so add things to the check + addInheritedFields(c, check, pos, result) semRecordNodeAux(c, n.sons[2], check, pos, result.n, result) if n.sons[0].kind != nkEmpty: # dummy symbol for `pragma`: @@ -934,14 +938,18 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, def = fitNode(c, typ, def) if not hasType and not hasDefault: if isType: localError(a.info, "':' expected") - let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything - if tdef == tyAnything: - message(a.info, warnTypelessParam, renderTree(n)) - typ = newTypeS(tdef, c) - - if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue + if kind in {skTemplate, skMacro}: + typ = newTypeS(tyExpr, c) + elif skipTypes(typ, {tyGenericInst}).kind == tyEmpty: + continue for j in countup(0, length-3): var arg = newSymG(skParam, a.sons[j], c) + if not hasType and not hasDefault and kind notin {skTemplate, skMacro}: + let param = strTableGet(c.signatures, arg.name) + if param != nil: typ = param.typ + else: + localError(a.info, "typeless parameters are obsolete") + typ = errorType(c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) let finalType = if lifted != nil: lifted else: typ.skipIntLit @@ -1307,11 +1315,6 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) of nkBlockType: result = semBlockType(c, n, prev) - of nkSharedTy: - checkSonsLen(n, 1) - result = semTypeNode(c, n.sons[0], prev) - result = freshType(result, prev) - result.flags.incl(tfShared) else: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) @@ -1387,15 +1390,6 @@ proc processMagicType(c: PContext, m: PSym) = rawAddSon(m.typ, newTypeS(tyNone, c)) of mPNimrodNode: incl m.typ.flags, tfTriggersCompileTime - of mShared: - setMagicType(m, tyObject, 0) - m.typ.n = newNodeI(nkRecList, m.info) - incl m.typ.flags, tfShared - of mGuarded: - setMagicType(m, tyObject, 0) - m.typ.n = newNodeI(nkRecList, m.info) - incl m.typ.flags, tfShared - rawAddSon(m.typ, sysTypeFromName"shared") else: localError(m.info, errTypeExpected) proc semGenericConstraints(c: PContext, x: PType): PType = diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index a7f28feec..d20704a2a 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -14,22 +14,11 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer const tfInstClearedFlags = {tfHasMeta} -proc sharedPtrCheck(info: TLineInfo, t: PType) = - if t.kind == tyPtr and t.len > 1: - if t.sons[0].sym.magic == mShared: - incl(t.flags, tfShared) - #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded) - if tfHasGCedMem in t.flags or t.isGCedMem: - localError(info, errGenerated, - "shared memory may not refer to GC'ed thread local memory") - proc checkPartialConstructedType(info: TLineInfo, t: PType) = if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: localError(info, errInvalidPragmaX, "acyclic") elif t.kind == tyVar and t.sons[0].kind == tyVar: localError(info, errVarVarTypeNotAllowed) - else: - sharedPtrCheck(info, t) proc checkConstructedType*(info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) @@ -40,8 +29,6 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) = localError(info, errVarVarTypeNotAllowed) elif computeSize(t) == szIllegalRecursion: localError(info, errIllegalRecursionInTypeX, typeToString(t)) - else: - sharedPtrCheck(info, t) when false: if t.kind == tyObject and t.sons[0] != nil: if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 96df0c5c6..ceadc2fea 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -37,6 +37,7 @@ type # is this a top-level symbol or a nested proc? call*: PNode # modified call bindings*: TIdTable # maps types to types + magic*: TMagic # magic of operation baseTypeMatch: bool # needed for conversions from T to openarray[T] # for example fauxMatch*: TTypeKind # the match was successful only due to the use @@ -114,6 +115,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, c.calleeScope = 1 else: c.calleeScope = calleeScope + c.magic = c.calleeSym.magic initIdTable(c.bindings) c.errors = nil if binding != nil and callee.kind in routineKinds: @@ -1691,7 +1693,7 @@ proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) = matchesAux(c, n, nOrig, m, marker) proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = - if m.calleeSym != nil and m.calleeSym.magic in {mArrGet, mArrPut}: + if m.magic in {mArrGet, mArrPut}: m.state = csMatch m.call = n return diff --git a/compiler/types.nim b/compiler/types.nim index 71ab84022..9aa991086 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -412,7 +412,6 @@ const const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg} proc addTypeFlags(name: var string, typ: PType) {.inline.} = - if tfShared in typ.flags: name = "shared " & name if tfNotNil in typ.flags: name.add(" not nil") proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 0a0534118..3e0e05a94 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -66,6 +66,7 @@ type wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wAsmNoStackFrame, wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks, + wPartial, wAuto, wBool, wCatch, wChar, wClass, wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, @@ -151,7 +152,7 @@ const "computedgoto", "injectstmt", "experimental", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", - "guard", "locks", + "guard", "locks", "partial", "auto", "bool", "catch", "char", "class", "const_cast", "default", "delete", "double", |