diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 6 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 76 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 33 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 14 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 96 | ||||
-rw-r--r-- | compiler/cgen.nim | 34 | ||||
-rw-r--r-- | compiler/evaltempl.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 11 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 6 | ||||
-rw-r--r-- | compiler/lookups.nim | 15 | ||||
-rw-r--r-- | compiler/nimsuggest/nimsuggest.nim.cfg | 1 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 2 | ||||
-rw-r--r-- | compiler/parser.nim | 5 | ||||
-rw-r--r-- | compiler/pragmas.nim | 4 | ||||
-rw-r--r-- | compiler/sem.nim | 26 | ||||
-rw-r--r-- | compiler/semasgn.nim | 2 | ||||
-rw-r--r-- | compiler/semcall.nim | 2 | ||||
-rw-r--r-- | compiler/semdata.nim | 3 | ||||
-rw-r--r-- | compiler/semexprs.nim | 5 | ||||
-rw-r--r-- | compiler/semfields.nim | 2 | ||||
-rw-r--r-- | compiler/semgnrc.nim | 52 | ||||
-rw-r--r-- | compiler/semstmts.nim | 5 | ||||
-rw-r--r-- | compiler/semtempl.nim | 10 | ||||
-rw-r--r-- | compiler/semtypes.nim | 3 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 12 | ||||
-rw-r--r-- | compiler/suggest.nim | 23 | ||||
-rw-r--r-- | compiler/vm.nim | 8 | ||||
-rw-r--r-- | compiler/vmdef.nim | 1 |
28 files changed, 289 insertions, 170 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d487b5380..f7c1a07ed 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -655,7 +655,6 @@ type locGlobalVar, # location is a global variable locParam, # location is a parameter locField, # location is a record field - locArrayElem, # location is an array element locExpr, # "location" is really an expression locProc, # location is a proc (an address of a procedure) locData, # location is a constant @@ -669,14 +668,15 @@ type lfDynamicLib, # link symbol to dynamic library lfExportLib, # export symbol for dynamic library generation lfHeader, # include header file for symbol - lfImportCompilerProc # ``importc`` of a compilerproc + lfImportCompilerProc, # ``importc`` of a compilerproc + lfSingleUse # no location yet and will only be used once TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStack, # location is on hardware stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] - TLoc*{.final.} = object + TLoc* = object k*: TLocKind # kind of location s*: TStorageLoc flags*: TLocFlags # location's flags diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index cb8dcc25b..ad9d18257 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, genAssignment(p, d, tmp, {}) # no need for deep copying else: app(pl, ~")") - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~");$n") line(p, cpsStmts, pl) @@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs, tyArray, tyArrayConstr: "($1)+($2), ($3)-($2)+1" of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): "(*$1)->data+($2), ($3)-($2)+1" else: "$1->data+($2), ($3)-($2)+1" @@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs: result = ropef("$1, $1Len0", [rdLoc(a)]) of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) else: result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) @@ -123,10 +133,14 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope = var n = if n.kind != nkHiddenAddr: n else: n.sons[0] result = openArrayLoc(p, n) elif ccgIntroducedPtr(param): - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = addrLoc(a) + elif p.module.compileToCpp and param.typ.kind == tyVar and + n.kind == nkHiddenAddr: + initLocExprSingleUse(p, n.sons[0], a) + result = rdLoc(a) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genArgNoParam(p: BProc, n: PNode): PRope = @@ -134,7 +148,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope = if n.kind == nkStringToCString: result = genArgStringToCString(p, n) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -274,26 +288,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: + var ri = ri[i] + while ri.kind == nkObjDownConv: ri = ri[0] if typ.sons[i].kind == tyVar: - let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i] - if x.kind in {nkHiddenDeref, nkDerefExpr}: - result = genArgNoParam(p, x[0]) - result.app("->") - elif x.typ.kind in {tyVar, tyPtr}: + let x = if ri.kind == nkHiddenAddr: ri[0] else: ri + if x.typ.kind == tyPtr: result = genArgNoParam(p, x) result.app("->") + elif x.kind in {nkHiddenDeref, nkDerefExpr}: + result = genArgNoParam(p, x[0]) + result.app("->") else: result = genArgNoParam(p, x) result.app(".") elif typ.sons[i].kind == tyPtr: - if ri.sons[i].kind in {nkAddr, nkHiddenAddr}: - result = genArgNoParam(p, ri.sons[i][0]) + if ri.kind in {nkAddr, nkHiddenAddr}: + result = genArgNoParam(p, ri[0]) result.app(".") else: - result = genArgNoParam(p, ri.sons[i]) + result = genArgNoParam(p, ri) result.app("->") else: - result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) + result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result.app(".") proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = @@ -367,12 +383,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri.sons[0].typ, abstractInst) if typ.sons[0] != nil: - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~";$n") line(p, cpsStmts, pl) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 591b6d76f..bd116d6fb 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -215,6 +215,7 @@ proc asgnComplexity(n: PNode): int = else: discard proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc = + assert field != nil result.k = locField result.s = a.s result.t = t @@ -229,7 +230,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = flags - {needToCopy} else: flags - let t = skipTypes(dest.t, abstractInst) + let t = skipTypes(dest.t, abstractInst).getUniqueType() for i in 0 .. <t.len: let t = t.sons[i] let field = ropef("Field$1", i.toRope) @@ -336,6 +337,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: discard getTypeDesc(p.module, ty) + ty = getUniqueType(ty) internalAssert ty.n != nil genOptAsgnObject(p, dest, src, flags, ty.n) else: @@ -660,9 +662,13 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), getSimpleTypeDesc(p.module, e.typ)])) +proc isCppRef(p: BProc; typ: PType): bool {.inline.} = + result = p.module.compileToCpp and + skipTypes(typ, abstractInst).kind == tyVar + proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = let mt = mapType(e.sons[0].typ) - if mt in {ctArray, ctPtrToArray} and not enforceDeref: + if (mt in {ctArray, ctPtrToArray} and not enforceDeref): # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? #if e[0].kind != nkBracketExpr: @@ -670,12 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = expr(p, e.sons[0], d) else: var a: TLoc - initLocExpr(p, e.sons[0], a) + initLocExprSingleUse(p, e.sons[0], a) case skipTypes(a.t, abstractInst).kind of tyRef: d.s = OnHeap of tyVar: d.s = OnUnknown + if p.module.compileToCpp: + putIntoDest(p, d, e.typ, rdLoc(a)) + return of tyPtr: d.s = OnUnknown # BUGFIX! else: internalError(e.info, "genDeref " & $a.t.kind) @@ -696,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[0], a) putIntoDest(p, d, e.typ, con("&", a.r)) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(e.sons[0].typ) == ctArray: + elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): expr(p, e.sons[0], d) else: var a: TLoc @@ -1120,7 +1129,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var r = rdLoc(tmp) if isRef: rawGenNew(p, tmp, nil) - t = t.sons[0].skipTypes(abstractInst) + t = t.lastSon.skipTypes(abstractInst) r = ropef("(*$1)", r) gcUsage(e) else: @@ -1131,7 +1140,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp2: TLoc tmp2.r = r var field: PSym = nil - var ty = t + var ty = getUniqueType(t) while ty != nil: field = lookupInRecord(ty.n, it.sons[0].sym.name) if field != nil: break @@ -1201,9 +1210,9 @@ proc genNewFinalize(p: BProc, e: PNode) = appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ getTypeDesc(p.module, refType), - ti, getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))]) + ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))]) genAssignment(p, a, b, {needToKeepAlive}) # set the object type: - bt = skipTypes(refType.sons[0], abstractRange) + bt = skipTypes(refType.lastSon, abstractRange) genObjectInit(p, cpsStmts, bt, a, false) gcUsage(e) @@ -1234,7 +1243,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = rfmt(nil, "(*$1)", r) + if t.kind != tyVar or not p.module.compileToCpp: + r = rfmt(nil, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: @@ -1861,7 +1871,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = ropef("(*$1)", [r]) + if t.kind != tyVar or not p.module.compileToCpp: + r = ropef("(*$1)", [r]) t = skipTypes(t.lastSon, abstractInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: @@ -2071,8 +2082,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genAsgn(p, n, fastAsgn=p.prc != nil) of nkDiscardStmt: if n.sons[0].kind != nkEmpty: - var a: TLoc genLineDir(p, n) + var a: TLoc initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index d7683f2c3..5d348c4e4 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -202,8 +202,19 @@ proc genSingleVar(p: BProc, a: PNode) = genVarPrototypeAux(generatedHeader, v) registerGcRoot(p, v) else: + let imm = isAssignedImmediately(a.sons[2]) + if imm and p.module.compileToCpp: + # C++ really doesn't like things like 'Foo f; f = x' as that invokes a + # parameterless constructor followed by an assignment operator. So we + # generate better code here: + genLineDir(p, a) + let decl = localVarDecl(p, v) + var tmp: TLoc + initLocExprSingleUse(p, a.sons[2], tmp) + lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc) + return assignLocalVar(p, v) - initLocalVar(p, v, isAssignedImmediately(a.sons[2])) + initLocalVar(p, v, imm) if a.sons[2].kind != nkEmpty: genLineDir(targetProc, a) @@ -932,6 +943,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope = var j = 0 while x[j] in {' ', '\t'}: inc(j) if x[j] in {'"', ':'}: + # don't modify the line if already in quotes or # some clobber register list: app(result, x); app(result, tnl) elif x[j] != '\0': diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 90996d9cd..823e3bc1b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -161,7 +161,13 @@ proc mapType(typ: PType): TCTypeKind = proc mapReturnType(typ: PType): TCTypeKind = if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr else: result = mapType(typ) - + +proc isImportedType(t: PType): bool = + result = t.sym != nil and sfImportc in t.sym.flags + +proc isImportedCppType(t: PType): bool = + result = t.sym != nil and sfInfixCall in t.sym.flags + proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc needsComplexAssignment(typ: PType): bool = result = containsGarbageCollectedRef(typ) @@ -170,19 +176,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and (typ.sons[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(rettype: PType): bool = +proc isInvalidReturnType(rettype: PType): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. if rettype == nil: result = true - else: + else: case mapType(rettype) - of ctArray: + of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) + if rettype.isImportedCppType or t.isImportedCppType: return false result = needsComplexAssignment(t) or (t.kind == tyObject and not isObjLackingTypeField(t)) else: result = false @@ -297,12 +304,6 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, else: app(params, ")") params = con("(", params) -proc isImportedType(t: PType): bool = - result = t.sym != nil and sfImportc in t.sym.flags - -proc isImportedCppType(t: PType): bool = - result = t.sym != nil and sfInfixCall in t.sym.flags - proc typeNameOrLiteral(t: PType, literal: string): PRope = if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): result = getTypeName(t) @@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) else: ae = sname fillLoc(field.loc, locField, field.typ, ae, OnUnknown) - let fieldType = field.loc.t.skipTypes(abstractInst) - if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: - appf(result, "$1 $2[SEQ_DECL_SIZE];$n", - [getTypeDescAux(m, fieldType.elemType, check), sname]) - else: - # don't use fieldType here because we need the - # tyGenericInst for C++ template support - appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) + # for importcpp'ed objects, we only need to set field.loc, but don't + # have to recurse via 'getTypeDescAux'. And not doing so prevents problems + # with heavily templatized C++ code: + if not isImportedCppType(rectype): + let fieldType = field.loc.t.skipTypes(abstractInst) + if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: + appf(result, "$1 $2[SEQ_DECL_SIZE];$n", + [getTypeDescAux(m, fieldType.elemType, check), sname]) + else: + # don't use fieldType here because we need the + # tyGenericInst for C++ template support + appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) else: internalError(n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = @@ -493,13 +498,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = if t.sym != nil: useHeader(m, t.sym) result = getTypePre(m, t) if result != nil: return - if containsOrIncl(check, t.id): + if containsOrIncl(check, t.id): + if isImportedCppType(typ) or isImportedCppType(t): return internalError("cannot generate C type for: " & typeToString(typ)) # XXX: this BUG is hard to fix -> we need to introduce helper structs, # but determining when this needs to be done is hard. We should split # C type generation into an analysis and a code generation phase somehow. case t.kind of tyRef, tyPtr, tyVar: + let star = if t.kind == tyVar and compileToCpp(m): "&" else: "*" var et = t.lastSon var etB = et.skipTypes(abstractInst) if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: @@ -510,12 +517,12 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and et.kind == tyGenericInst: - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) else: # no restriction! We have a forward declaration for structs let x = getUniqueType(etB) let name = getTypeForward(m, x) - result = con(name, "*") + result = con(name, star) idTablePut(m.typeCache, t, result) pushType(m, x) of tySequence: @@ -527,7 +534,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = pushType(m, x) else: # else we have a strong dependency :-( - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) idTablePut(m.typeCache, t, result) of tyOpenArray, tyVarargs: result = con(getTypeDescAux(m, t.sons[0], check), "*") @@ -696,16 +703,7 @@ proc getNimNode(m: BModule): PRope = result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)]) inc(m.typeNodes) -when false: - proc getNimType(m: BModule): PRope = - result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)]) - inc(m.nimTypes) - - proc allocMemTI(m: BModule, typ: PType, name: PRope) = - var tmp = getNimType(m) - appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name]) - -proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = +proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) = var nimtypeKind: int #allocMemTI(m, typ, name) if isObjLackingTypeField(typ): @@ -715,6 +713,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = var size: PRope if tfIncompleteStruct in typ.flags: size = toRope"void*" + elif m.compileToCpp: size = getTypeDesc(m, origType) else: size = getTypeDesc(m, typ) appf(m.s[cfsTypeInit3], "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", @@ -730,13 +729,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", [name, toRope(typeToString(typ))]) -proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = +proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) = var base: PRope if (sonsLen(typ) > 0) and (typ.sons[0] != nil): base = genTypeInfo(m, typ.sons[0]) else: base = toRope("0") - genTypeInfoAuxBase(m, typ, name, base) + genTypeInfoAuxBase(m, typ, origType, name, base) proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = # bugfix: we need to search the type that contains the discriminator: @@ -814,11 +813,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) = field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)]) else: internalError(n.info, "genObjectFields") -proc genObjectInfo(m: BModule, typ: PType, name: PRope) = - if typ.kind == tyObject: genTypeInfoAux(m, typ, name) - else: genTypeInfoAuxBase(m, typ, name, toRope("0")) +proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) = + if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name) + else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0")) var tmp = getNimNode(m) - genObjectFields(m, typ, typ.n, tmp) + if not isImportedCppType(typ): + genObjectFields(m, typ, typ.n, tmp) appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) var t = typ.sons[0] while t != nil: @@ -827,7 +827,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) = t = t.sons[0] proc genTupleInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, toRope("0")) + genTypeInfoAuxBase(m, typ, typ, name, toRope("0")) var expr = getNimNode(m) var length = sonsLen(typ) if length > 0: @@ -854,7 +854,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = # optimizations here: The ``typ`` field is never set, as it is redundant # anyway. We generate a cstring array and a loop over it. Exceptional # positions will be reset after the loop. - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var nodePtrs = getTempName() var length = sonsLen(typ.n) appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", @@ -894,13 +894,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = proc genSetInfo(m: BModule, typ: PType, name: PRope) = assert(typ.sons[0] != nil) - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var tmp = getNimNode(m) appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", [tmp, toRope(firstOrd(typ)), name]) proc genArrayInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1])) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1])) proc fakeClosureType(owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] @@ -946,23 +946,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope = case t.kind of tyEmpty: result = toRope"0" of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") of tyProc: if t.callConv != ccClosure: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") else: genTupleInfo(m, fakeClosureType(t.owner), result) of tySequence, tyRef: - genTypeInfoAux(m, t, result) + genTypeInfoAux(m, t, t, result) if gSelectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, t, tiNew) appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) - of tyPtr, tyRange: genTypeInfoAux(m, t, result) + of tyPtr, tyRange: genTypeInfoAux(m, t, t, result) of tyArrayConstr, tyArray: genArrayInfo(m, t, result) of tySet: genSetInfo(m, t, result) of tyEnum: genEnumInfo(m, t, result) - of tyObject: genObjectInfo(m, t, result) - of tyTuple: + of tyObject: genObjectInfo(m, t, origType, result) + of tyTuple: # if t.n != nil: genObjectInfo(m, t, result) # else: # BUGFIX: use consistently RTTI without proper field names; otherwise diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 480c131ae..e16d5d0ce 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -402,11 +402,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) - if gCmd == cmdCompileToLLVM: - result.r = con("%LOC", toRope(p.labels)) - else: - result.r = con("LOC", toRope(p.labels)) - linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) + result.r = con("LOC", toRope(p.labels)) + linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp #result.a = - 1 result.t = getUniqueType(t) @@ -494,22 +491,26 @@ proc localDebugInfo(p: BProc, s: PSym) = inc(p.maxFrameLen) inc p.blocks[p.blocks.len-1].frameLen -proc assignLocalVar(p: BProc, s: PSym) = - #assert(s.loc.k == locNone) // not yet assigned - # this need not be fullfilled for inline procs; they are regenerated - # for each module that uses them! +proc localVarDecl(p: BProc; s: PSym): PRope = if s.loc.k == locNone: fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) - var decl = getTypeDesc(p.module, s.loc.t) + result = getTypeDesc(p.module, s.loc.t) if s.constraint.isNil: - if sfRegister in s.flags: app(decl, " register") + if sfRegister in s.flags: app(result, " register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(decl, " GC_GUARD") - if sfVolatile in s.flags: app(decl, " volatile") - appf(decl, " $1;$n", [s.loc.r]) + if sfVolatile in s.flags: app(result, " volatile") + app(result, " ") + app(result, s.loc.r) else: - decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r) + result = ropef(s.cgDeclFrmt, result, s.loc.r) + +proc assignLocalVar(p: BProc, s: PSym) = + #assert(s.loc.k == locNone) // not yet assigned + # this need not be fullfilled for inline procs; they are regenerated + # for each module that uses them! + let decl = localVarDecl(p, s).con(";" & tnl) line(p, cpsLocals, decl) localDebugInfo(p, s) @@ -586,6 +587,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = initLoc(result, locNone, e.typ, OnUnknown) expr(p, e, result) +proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = + initLoc(result, locNone, e.typ, OnUnknown) + result.flags.incl lfSingleUse + expr(p, e, result) + proc lenField(p: BProc): PRope = result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 946be68f8..29657a2ae 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -93,7 +93,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode = evalTemplateAux(body, args, ctx, result) if result.len == 1: result = result.sons[0] else: - globalError(result.info, errIllFormedAstX, + localError(result.info, errIllFormedAstX, renderTree(result, {renderNoComments})) else: result = copyNode(body) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c48bf8c91..beb84b00a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1448,9 +1448,18 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = var dest = skipTypes(n.typ, abstractVarRange) var src = skipTypes(n.sons[1].typ, abstractVarRange) gen(p, n.sons[1], r) - if (dest.kind != src.kind) and (src.kind == tyBool): + if dest.kind == src.kind: + # no-op conversion + return + case dest.kind: + of tyBool: r.res = ropef("(($1)? 1:0)" | "toBool($#)", [r.res]) r.kind = resExpr + of tyInt: + r.res = ropef("($1|0)", [r.res]) + else: + # TODO: What types must we handle here? + discard proc upConv(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0], r) # XXX diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 6fa95fda2..b7dc277a4 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -719,7 +719,7 @@ proc outerProcSons(o: POuterContext, n: PNode, it: TIter) = let x = transformOuterProc(o, n.sons[i], it) if x != nil: n.sons[i] = x -proc liftIterSym(n: PNode): PNode = +proc liftIterSym(n: PNode; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) let iter = n.sym assert iter.kind == skClosureIterator @@ -727,7 +727,7 @@ proc liftIterSym(n: PNode): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let hp = getHiddenParam(iter) - let env = newSym(skLet, iter.name, iter.owner, iter.info) + let env = newSym(skLet, iter.name, owner, n.info) env.typ = hp.typ env.flags = hp.flags var v = newNodeI(nkVarSection, n.info) @@ -867,7 +867,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode = # XXX why doesn't this work? var closure = PEnv(idTableGet(o.lambdasToEnv, local)) if closure.isNil: - return liftIterSym(n) + return liftIterSym(n, o.fn) else: let createdVar = generateIterClosureCreation(o, closure, closure.attachedNode) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 29be693dd..21d07f280 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -22,7 +22,9 @@ proc considerQuotedIdent*(n: PNode): PIdent = of nkSym: result = n.sym.name of nkAccQuoted: case n.len - of 0: globalError(n.info, errIdentifierExpected, renderTree(n)) + of 0: + localError(n.info, errIdentifierExpected, renderTree(n)) + result = getIdent"<Error>" of 1: result = considerQuotedIdent(n.sons[0]) else: var id = "" @@ -31,12 +33,15 @@ proc considerQuotedIdent*(n: PNode): PIdent = case x.kind of nkIdent: id.add(x.ident.s) of nkSym: id.add(x.sym.name.s) - else: globalError(n.info, errIdentifierExpected, renderTree(n)) + else: + localError(n.info, errIdentifierExpected, renderTree(n)) + return getIdent"<Error>" result = getIdent(id) of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name else: - globalError(n.info, errIdentifierExpected, renderTree(n)) - + localError(n.info, errIdentifierExpected, renderTree(n)) + result = getIdent"<Error>" + template addSym*(scope: PScope, s: PSym) = strTableAdd(scope.symbols, s) diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg index d1a1e6b62..062092f16 100644 --- a/compiler/nimsuggest/nimsuggest.nim.cfg +++ b/compiler/nimsuggest/nimsuggest.nim.cfg @@ -9,7 +9,6 @@ path:"$lib/packages/docutils" path:"$nim/compiler" define:useStdoutAsStdmsg -symbol:nimsuggest define:nimsuggest cs:partial diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 300abea1e..8db786a25 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -41,7 +41,7 @@ type const MaxStackSize* = 64 ## max required stack size by the VM -proc patternError(n: PNode) = +proc patternError(n: PNode) = localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) proc add(code: var TPatternCode, op: TOpcode) {.inline.} = diff --git a/compiler/parser.nim b/compiler/parser.nim index adf3b72a3..aae0ce7f9 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -324,7 +324,10 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = getTok(p) else: parMessage(p, errIdentifierExpected, p.tok) - getTok(p) # BUGFIX: We must consume a token here to prevent endless loops! + # BUGFIX: We must consume a token here to prevent endless loops! + # But: this really sucks for idetools and keywords, so we don't do it + # if it is a keyword: + if not isKeyword(p.tok.tokType): getTok(p) result = ast.emptyNode proc indexExpr(p: var TParser): PNode = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 735460906..90f87696b 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -447,7 +447,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = addSon(result, newStrNode(nkStrLit, $marker)) if c < 0: break a = c + 1 - else: illFormedAst(n) + else: + illFormedAstLocal(n) + result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = discard getStrLitNode(c, n) diff --git a/compiler/sem.nim b/compiler/sem.nim index 90037fccd..214f471d6 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -47,6 +47,24 @@ proc finishMethod(c: PContext, s: PSym) proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode +template semIdeForTemplateOrGenericCheck(n, requiresCheck) = + # we check quickly if the node is where the cursor is + when defined(nimsuggest): + if n.info.fileIndex == gTrackPos.fileIndex and n.info.line == gTrackPos.line: + requiresCheck = true + +template semIdeForTemplateOrGeneric(c: PContext; n: PNode; + requiresCheck: bool) = + # use only for idetools support; this is pretty slow so generics and + # templates perform some quick check whether the cursor is actually in + # the generic or template. + when defined(nimsuggest): + assert gCmd == cmdIdeTools + if requiresCheck: + if optIdeDebug in gGlobalOptions: + echo "passing to safeSemExpr: ", renderTree(n) + discard safeSemExpr(c, n) + proc typeMismatch(n: PNode, formal, actual: PType) = if formal.kind != tyError and actual.kind != tyError: localError(n.info, errGenerated, msgKindToString(errTypeMismatch) & @@ -359,13 +377,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode = localError(n.info, errConstExprExpected) result = nn -type - TSemGenericFlag = enum - withinBind, withinTypeDesc, withinMixin - TSemGenericFlags = set[TSemGenericFlag] - -proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var IntSet): PNode +proc semGenericStmt(c: PContext, n: PNode): PNode include semtypes, semtempl, semgnrc, semstmts, semexprs diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 0b68bc897..71ebbbafd 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -101,7 +101,7 @@ proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) = of nkRecList: for t in items(typ): liftBodyObj(c, t, x, y) else: - illFormedAst(typ) + illFormedAstLocal(typ) proc newAsgnCall(op: PSym; x, y: PNode): PNode = result = newNodeI(nkCall, x.info) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index cdfdfc9d0..5cb713030 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -315,6 +315,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, var r = resolveOverloads(c, n, nOrig, filter, errors) if r.state == csMatch: result = semResolvedCall(c, n, r) else: + # get rid of the deref again for a better error message: + n.sons[1] = n.sons[1].sons[0] notFoundError(c, n, errors) else: notFoundError(c, n, errors) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index bb82db292..157761591 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -307,6 +307,9 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} = proc illFormedAst*(n: PNode) = globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) +proc illFormedAstLocal*(n: PNode) = + localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) + proc checkSonsLen*(n: PNode, length: int) = if sonsLen(n) != length: illFormedAst(n) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 34a9cd1dd..ab1b75994 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -956,9 +956,10 @@ proc makeDeref(n: PNode): PNode = t = skipTypes(t.sons[0], {tyGenericInst}) while t.kind in {tyPtr, tyRef}: var a = result - result = newNodeIT(nkHiddenDeref, n.info, t.sons[0]) + let baseTyp = t.lastSon + result = newNodeIT(nkHiddenDeref, n.info, baseTyp) addSon(result, a) - t = skipTypes(t.lastSon, {tyGenericInst}) + t = skipTypes(baseTyp, {tyGenericInst}) const tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass} diff --git a/compiler/semfields.nim b/compiler/semfields.nim index f02c542ed..823bef225 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -98,7 +98,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = of nkRecList: for t in items(typ): semForObjectFields(c, t, forLoop, father) else: - illFormedAst(typ) + illFormedAstLocal(typ) proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = # so that 'break' etc. work as expected, we produce diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index d69fdb04a..13941fa58 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -25,10 +25,23 @@ proc getIdentNode(n: PNode): PNode = else: illFormedAst(n) result = n - + +type + GenericCtx = object + toMixin: IntSet + cursorInBody: bool # only for nimsuggest + +type + TSemGenericFlag = enum + withinBind, withinTypeDesc, withinMixin + TSemGenericFlags = set[TSemGenericFlag] + +proc semGenericStmt(c: PContext, n: PNode, + flags: TSemGenericFlags, ctx: var GenericCtx): PNode + proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var IntSet): PNode = + ctx: var GenericCtx): PNode = openScope(c) result = semGenericStmt(c, n, flags, ctx) closeScope(c) @@ -37,7 +50,8 @@ template macroToExpand(s: expr): expr = s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags) proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, - ctx: var IntSet): PNode = + ctx: var GenericCtx): PNode = + semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) incl(s.flags, sfUsed) case s.kind of skUnknown: @@ -83,17 +97,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, styleCheckUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var IntSet): PNode = + ctx: var GenericCtx): PNode = result = n let ident = considerQuotedIdent(n) var s = searchInScopes(c, ident).skipAlias(n) if s == nil: - if ident.id notin ctx and withinMixin notin flags: + if ident.id notin ctx.toMixin and withinMixin notin flags: localError(n.info, errUndeclaredIdentifier, ident.s) else: if withinBind in flags: result = symChoice(c, n, s, scClosed) - elif s.name.id in ctx: + elif s.name.id in ctx.toMixin: result = symChoice(c, n, s, scForceOpen) else: result = semGenericStmtSymbol(c, n, s, ctx) @@ -105,8 +119,10 @@ proc newDot(n, b: PNode): PNode = result.add(b) proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var IntSet; isMacro: var bool): PNode = + ctx: var GenericCtx; isMacro: var bool): PNode = assert n.kind == nkDotExpr + semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) + let luf = if withinMixin notin flags: {checkUndeclared} else: {} var s = qualifiedLookUp(c, n, luf) @@ -122,7 +138,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, isMacro = s.kind in {skTemplate, skMacro} if withinBind in flags: result = newDot(result, symChoice(c, n, s, scClosed)) - elif s.name.id in ctx: + elif s.name.id in ctx.toMixin: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: let sym = semGenericStmtSymbol(c, n, s, ctx) @@ -137,9 +153,11 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = styleCheckDef(n.info, s, kind) proc semGenericStmt(c: PContext, n: PNode, - flags: TSemGenericFlags, ctx: var IntSet): PNode = + flags: TSemGenericFlags, ctx: var GenericCtx): PNode = result = n - if gCmd == cmdIdeTools: suggestStmt(c, n) + #if gCmd == cmdIdeTools: suggestStmt(c, n) + semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody) + case n.kind of nkIdent, nkAccQuoted: result = lookup(c, n, flags, ctx) @@ -162,14 +180,15 @@ proc semGenericStmt(c: PContext, n: PNode, of nkBind: result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx) of nkMixinStmt: - result = semMixinStmt(c, n, ctx) + result = semMixinStmt(c, n, ctx.toMixin) of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: # check if it is an expression macro: checkMinSonsLen(n, 1) let fn = n.sons[0] var s = qualifiedLookUp(c, fn, {}) if s == nil and withinMixin notin flags and - fn.kind in {nkIdent, nkAccQuoted} and considerQuotedIdent(fn).id notin ctx: + fn.kind in {nkIdent, nkAccQuoted} and + considerQuotedIdent(fn).id notin ctx.toMixin: localError(n.info, errUndeclaredIdentifier, fn.renderTree) var first = 0 @@ -177,7 +196,7 @@ proc semGenericStmt(c: PContext, n: PNode, if s != nil: incl(s.flags, sfUsed) mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} - let scOption = if s.name.id in ctx: scForceOpen else: scOpen + let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen case s.kind of skMacro: if macroToExpand(s): @@ -377,4 +396,9 @@ proc semGenericStmt(c: PContext, n: PNode, else: for i in countup(0, sonsLen(n) - 1): result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx) - + +proc semGenericStmt(c: PContext, n: PNode): PNode = + var ctx: GenericCtx + ctx.toMixin = initIntset() + result = semGenericStmt(c, n, {}, ctx) + semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 565d4db06..3fe3e40f0 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1060,8 +1060,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, else: if s.typ.sons[0] != nil and kind notin skIterators: addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) - var toBind = initIntSet() - n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind) + openScope(c) + n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) + closeScope(c) fixupInstantiatedSymbols(c, s) if sfImportc in s.flags: # so we just ignore the body after semantic checking for importc: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index e2c46d3ab..3477d3d6f 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -105,10 +105,11 @@ proc replaceIdentBySym(n: var PNode, s: PNode) = else: illFormedAst(n) type - TemplCtx {.pure, final.} = object + TemplCtx = object c: PContext toBind, toMixin, toInject: IntSet owner: PSym + cursorInBody: bool # only for nimsuggest proc getIdentNode(c: var TemplCtx, n: PNode): PNode = case n.kind @@ -259,8 +260,9 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) = addLocalDecl(c, a.sons[j], symKind) proc semPattern(c: PContext, n: PNode): PNode -proc semTemplBody(c: var TemplCtx, n: PNode): PNode = +proc semTemplBody(c: var TemplCtx, n: PNode): PNode = result = n + semIdeForTemplateOrGenericCheck(n, c.cursorInBody) case n.kind of nkIdent: if n.ident.id in c.toInject: return n @@ -416,8 +418,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): result.sons[i] = semTemplBody(c, n.sons[i]) -proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = +proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = result = n + semIdeForTemplateOrGenericCheck(n, c.cursorInBody) case n.kind of nkIdent: let s = qualifiedLookUp(c.c, n, {}) @@ -524,6 +527,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}: n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) # only parameters are resolved, no type checking is performed + semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody) closeScope(c) popOwner() s.ast = n diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index da892dea8..8d1655593 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1178,8 +1178,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = return errorType(c) result = typeExpr.typ.base if result.isMetaType: - var toBind = initIntSet() - var preprocessed = semGenericStmt(c, n, {}, toBind) + var preprocessed = semGenericStmt(c, n) return makeTypeFromExpr(c, preprocessed) of nkIdent, nkAccQuoted: var s = semTypeIdent(c, n) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 549f1f9ad..2e37f3bf1 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1300,7 +1300,6 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, # incorrect to simply use the first fitting match. However, to implement # this correctly is inefficient. We have to copy `m` here to be able to # roll back the side effects of the unification algorithm. - let c = m.c var x, y, z: TCandidate initCandidate(c, x, m.callee) @@ -1329,12 +1328,15 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, y = z # z is as good as x if x.state == csEmpty: result = nil - elif (y.state == csMatch) and (cmpCandidates(x, y) == 0): + elif y.state == csMatch and cmpCandidates(x, y) == 0: if x.state != csMatch: internalError(arg.info, "x.state is not csMatch") - # ambiguous: more than one symbol fits - result = nil - else: + # ambiguous: more than one symbol fits! + # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match + # anyway: + if f.kind == tyExpr: result = arg + else: result = nil + else: # only one valid interpretation found: markUsed(arg.info, arg.sons[best].sym) styleCheckUse(arg.info, arg.sons[best].sym) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 7f8caca6e..6b168670c 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -256,19 +256,6 @@ proc findClosestSym(n: PNode): PNode = result = findClosestSym(n.sons[i]) if result != nil: return -proc safeSemExpr(c: PContext, n: PNode): PNode = - try: - result = c.semExpr(c, n) - except ERecoverableError: - result = ast.emptyNode - -proc fuzzySemCheck(c: PContext, n: PNode): PNode = - result = safeSemExpr(c, n) - if result == nil or result.kind == nkEmpty: - result = newNodeI(n.kind, n.info) - if n.kind notin {nkNone..nkNilLit}: - for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i])) - var usageSym*: PSym lastLineInfo: TLineInfo @@ -312,6 +299,13 @@ proc useSym*(sym: PSym): PNode = result = newSymNode(sym) markUsed(result.info, sym) +proc safeSemExpr*(c: PContext, n: PNode): PNode = + # use only for idetools support! + try: + result = c.semExpr(c, n) + except ERecoverableError: + result = ast.emptyNode + proc suggestExpr*(c: PContext, node: PNode) = if nfIsCursor notin node.flags: if gTrackPos.line < 0: return @@ -328,6 +322,9 @@ proc suggestExpr*(c: PContext, node: PNode) = if n.kind == nkDotExpr: var obj = safeSemExpr(c, n.sons[0]) suggestFieldAccess(c, obj, outputs) + if optIdeDebug in gGlobalOptions: + echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ) + #writeStackTrace() else: suggestEverything(c, n, outputs) diff --git a/compiler/vm.nim b/compiler/vm.nim index 7edbb3fd2..b682b4e25 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1364,9 +1364,11 @@ var globalCtx: PCtx proc setupGlobalCtx(module: PSym) = - if globalCtx.isNil: globalCtx = newCtx(module) - else: refresh(globalCtx, module) - registerAdditionalOps(globalCtx) + if globalCtx.isNil: + globalCtx = newCtx(module) + registerAdditionalOps(globalCtx) + else: + refresh(globalCtx, module) proc myOpen(module: PSym): PPassContext = #var c = newEvalContext(module, emRepl) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 3d49cb130..90b9f2517 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx = proc refresh*(c: PCtx, module: PSym) = c.module = module c.prc = PProc(blocks: @[]) + c.loopIterations = MaxLoopIterations proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = c.callbacks.add((name, callback)) |