diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 7 | ||||
-rw-r--r-- | compiler/evals.nim | 21 | ||||
-rw-r--r-- | compiler/options.nim | 2 | ||||
-rw-r--r-- | compiler/semdata.nim | 10 | ||||
-rw-r--r-- | compiler/semexprs.nim | 2 | ||||
-rw-r--r-- | compiler/semfold.nim | 16 | ||||
-rw-r--r-- | compiler/seminst.nim | 49 | ||||
-rw-r--r-- | compiler/semmagic.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 16 | ||||
-rw-r--r-- | compiler/semtypes.nim | 35 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 10 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 8 |
12 files changed, 124 insertions, 54 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index bb015ea27..bb06e7163 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -626,6 +626,7 @@ type case kind*: TSymKind of skType: typeInstCache*: seq[PType] + typScope*: PScope of routineKinds: procInstCache*: seq[PInstantiation] scope*: PScope # the scope where the proc was defined @@ -799,9 +800,9 @@ const # imported via 'importc: "fullname"' and no format string. # creator procs: -proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym, +proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym, info: TLineInfo): PSym -proc NewType*(kind: TTypeKind, owner: PSym): PType +proc newType*(kind: TTypeKind, owner: PSym): PType proc newNode*(kind: TNodeKind): PNode proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode @@ -1111,7 +1112,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym = result.loc = s.loc result.annex = s.annex # BUGFIX -proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym, +proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym, info: TLineInfo): PSym = # generates a symbol and initializes the hash field too new(result) diff --git a/compiler/evals.nim b/compiler/evals.nim index 3f09664a7..053068ea4 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -904,18 +904,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode = code.info.line.int) #result.typ = newType(tyStmt, c.module) -proc evalTypeTrait*(n: PNode, context: PSym): PNode = - ## XXX: This should be pretty much guaranteed to be true - # by the type traits procs' signatures, but until the - # code is more mature it doesn't hurt to be extra safe - internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym - - let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc}) - case n.sons[0].sym.name.s.normalize +proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode = + InternalAssert operand.kind == nkSym + + let typ = operand.sym.typ.skipTypes({tyTypeDesc}) + case trait.sym.name.s.normalize of "name": - result = newStrNode(nkStrLit, typ.typeToString(preferExported)) + result = newStrNode(nkStrLit, typ.typeToString(preferName)) result.typ = newType(tyString, context) - result.info = n.info + result.info = trait.info else: internalAssert false @@ -1037,8 +1034,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mParseStmtToAst: result = evalParseStmt(c, n) of mExpandToAst: result = evalExpandToAst(c, n) of mTypeTrait: - n.sons[1] = evalAux(c, n.sons[1], {}) - result = evalTypeTrait(n, c.module) + let operand = evalAux(c, n.sons[1], {}) + result = evalTypeTrait(n[0], operand, c.module) of mIs: n.sons[1] = evalAux(c, n.sons[1], {}) result = evalIsOp(n) diff --git a/compiler/options.nim b/compiler/options.nim index 5f173d240..2b25b2650 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -156,6 +156,8 @@ var const oKeepVariableNames* = true +const oUseLateInstantiation* = false + proc mainCommandArg*: string = ## This is intended for commands like check or parse ## which will work on the main project file unless diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b9c32a680..8b04f4af5 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -225,14 +225,14 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = dest.owner = getCurrOwner() dest.size = - 1 -proc makeRangeType*(c: PContext, first, last: biggestInt, - info: TLineInfo): PType = +proc makeRangeType*(c: PContext; first, last: biggestInt; + info: TLineInfo; intType = getSysType(tyInt)): PType = var n = newNodeI(nkRange, info) - addSon(n, newIntNode(nkIntLit, first)) - addSon(n, newIntNode(nkIntLit, last)) + addSon(n, newIntTypeNode(nkIntLit, first, intType)) + addSon(n, newIntTypeNode(nkIntLit, last, intType)) result = newTypeS(tyRange, c) result.n = n - rawAddSon(result, getSysType(tyInt)) # basetype of range + addSonSkipIntLit(result, intType) # basetype of range proc markIndirect*(c: PContext, s: PSym) {.inline.} = if s.kind in {skProc, skConverter, skMethod, skIterator}: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 354cbcbd1..4d7ceffa9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -113,7 +113,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of skGenericParam: if s.typ.kind == tyExpr: result = newSymNode(s, n.info) - result.typ = s.typ.lastSon + result.typ = s.typ elif s.ast != nil: result = semExpr(c, s.ast) else: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 634ea8395..ca06ea1b6 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -561,9 +561,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode = case n.kind of nkSym: var s = n.sym - if s.kind == skEnumField: + case s.kind + of skEnumField: result = newIntNodeT(s.position, n) - elif s.kind == skConst: + of skConst: case s.magic of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n) of mCompileDate: result = newStrNodeT(times.getDateStr(), n) @@ -581,10 +582,17 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mNegInf: result = newFloatNodeT(NegInf, n) else: if sfFakeConst notin s.flags: result = copyTree(s.ast) - elif s.kind in {skProc, skMethod}: # BUGFIX + of {skProc, skMethod}: result = n - elif s.kind in {skType, skGenericParam}: + of skType: result = newSymNodeTypeDesc(s, n.info) + of skGenericParam: + if s.typ.kind == tyExpr: + result = s.typ.n + result.typ = s.typ.sons[0] + else: + result = newSymNodeTypeDesc(s, n.info) + else: nil of nkCharLit..nkNilLit: result = copyNode(n) of nkIfExpr: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 601072833..0cf5086a8 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -130,13 +130,50 @@ proc sideEffectsCheck(c: PContext, s: PSym) = s.ast.sons[genericParamsPos].kind == nkEmpty: c.threadEntries.add(s) +proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType = + InternalAssert invocation.kind == tyGenericInvokation + + let cacheHit = searchInstTypes(invocation) + if cacheHit != nil: + result = cacheHit + else: + let s = invocation.sons[0].sym + let oldScope = c.currentScope + c.currentScope = s.typScope + openScope(c) + pushInfoContext(info) + for i in 0 .. <s.typ.n.sons.len: + let genericParam = s.typ.n[i].sym + let symKind = if genericParam.typ.kind == tyExpr: skConst + else: skType + + var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info) + boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr}) + boundSym.ast = invocation.sons[i+1].n + addDecl(c, boundSym) + # XXX: copyTree would have been unnecessary here if semTypeNode + # didn't modify its input parameters. Currently, it does modify + # at least the record lists of the passed object and tuple types + var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil) + popInfoContext() + closeScope(c) + c.currentScope = oldScope + if instantiated != nil: + result = invocation + result.kind = tyGenericInst + result.sons.add instantiated + cacheTypeInst result + proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType = - var cl: TReplTypeVars - InitIdTable(cl.symMap) - InitIdTable(cl.typeMap) - cl.info = info - cl.c = c - result = ReplaceTypeVarsT(cl, header) + when oUseLateInstantiation: + lateInstantiateGeneric(c, header, info) + else: + var cl: TReplTypeVars + InitIdTable(cl.symMap) + InitIdTable(cl.typeMap) + cl.info = info + cl.c = c + result = ReplaceTypeVarsT(cl, header) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = result = instGenericContainer(c, n.info, header) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 41c379133..b9ef8b008 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -40,7 +40,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode = (typArg.kind == skParam and typArg.typ.sonsLen > 0): # This is either a type known to sem or a typedesc # param to a regular proc (again, known at instantiation) - result = evalTypeTrait(n, GetCurrOwner()) + result = evalTypeTrait(n[0], n[1], GetCurrOwner()) else: # a typedesc variable, pass unmodified to evals result = n diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 33c0adac1..a15b3e10a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -729,12 +729,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # like: mydata.seq rawAddSon(s.typ, newTypeS(tyEmpty, c)) s.ast = a - inc c.InGenericContext - var body = semTypeNode(c, a.sons[2], nil) - dec c.InGenericContext - if body != nil: - body.sym = s - body.size = -1 # could not be computed properly + when oUseLateInstantiation: + var body: PType = nil + s.typScope = c.currentScope.parent + else: + inc c.InGenericContext + var body = semTypeNode(c, a.sons[2], nil) + dec c.InGenericContext + if body != nil: + body.sym = s + body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body popOwner() closeScope(c) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8ae23f851..b02fa7c31 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -156,7 +156,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = LocalError(n.Info, errRangeIsEmpty) var a = semConstExpr(c, n[1]) var b = semConstExpr(c, n[2]) - if not sameType(a.typ, b.typ): + if not sameType(a.typ, b.typ): LocalError(n.info, errPureTypeMismatch) elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar, tyFloat..tyFloat128,tyUInt8..tyUInt32}: @@ -195,17 +195,19 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = else: let e = semExprWithType(c, n.sons[1], {efDetermineType}) if e.kind in {nkIntLit..nkUInt64Lit}: - indx = newTypeS(tyRange, c) - indx.n = newNodeI(nkRange, n.info) - addSon(indx.n, newIntTypeNode(e.kind, 0, e.typ)) - addSon(indx.n, newIntTypeNode(e.kind, e.intVal-1, e.typ)) - addSonSkipIntLit(indx, e.typ) + indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) + elif e.kind == nkSym and e.typ.kind == tyExpr: + if e.sym.ast != nil: return semArray(c, e.sym.ast, nil) + InternalAssert c.InGenericContext > 0 + if not isOrdinalType(e.typ.lastSon): + localError(n[1].info, errOrdinalTypeExpected) + indx = e.typ else: indx = e.typ.skipTypes({tyTypeDesc}) addSonSkipIntLit(result, indx) if indx.kind == tyGenericInst: indx = lastSon(indx) - if indx.kind != tyGenericParam: - if not isOrdinalType(indx): + if indx.kind notin {tyGenericParam, tyExpr}: + if not isOrdinalType(indx): LocalError(n.sons[1].info, errOrdinalTypeExpected) elif enumHasHoles(indx): LocalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s) @@ -587,6 +589,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = else: if sfGenSym notin param.flags: addDecl(c, param) +let typedescId = getIdent"typedesc" + proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, paramType: PType, paramName: string, info: TLineInfo, anon = false): PType = @@ -634,6 +638,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons)) of tyTypeDesc: if tfUnresolved notin paramType.flags: + # naked typedescs are not bindOnce types + if paramType.sonsLen == 0 and paramTypId != nil and + paramTypId.id == typedescId.id: paramTypId = nil result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons)) of tyDistinct: if paramType.sonsLen == 1: @@ -760,7 +767,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, r.flags.incl tfRetType result.sons[0] = skipIntLit(r) res.typ = result.sons[0] - + proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = checkMinSonsLen(n, 1) var length = sonsLen(n) @@ -846,7 +853,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = LocalError(n.info, errCannotInstantiateX, s.name.s) result = newOrPrevType(tyError, prev, c) else: - result = instGenericContainer(c, n, result) + when oUseLateInstantiation: + result = lateInstantiateGeneric(c, result, n.info) + else: + result = instGenericContainer(c, n, result) proc semTypeExpr(c: PContext, n: PNode): PType = var n = semExprWithType(c, n, {efDetermineType}) @@ -1073,8 +1083,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if constraint.kind != nkEmpty: typ = semTypeNode(c, constraint, nil) if typ.kind != tyExpr or typ.len == 0: - if typ.len == 0 and typ.kind == tyTypeDesc: - typ = newTypeS(tyGenericParam, c) + if typ.kind == tyTypeDesc: + if typ.len == 0: + typ = newTypeS(tyTypeDesc, c) else: typ = semGenericConstraints(c, typ) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 31fbc33e1..0c15c7248 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -31,7 +31,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) = if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: localError(info, errInheritanceOnlyWithNonFinalObjects) -proc searchInstTypes(key: PType): PType = +proc searchInstTypes*(key: PType): PType = let genericTyp = key.sons[0] InternalAssert genericTyp.kind == tyGenericBody and key.sons[0] == genericTyp and @@ -55,7 +55,7 @@ proc searchInstTypes(key: PType): PType = return inst -proc cacheTypeInst(inst: PType) = +proc cacheTypeInst*(inst: PType) = # XXX: add to module's generics # update the refcount let genericTyp = inst.sons[0] @@ -208,6 +208,12 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = of tyInt: result = skipIntLit(t) else: + if t.kind == tyArray: + let idxt = t.sons[0] + if idxt.kind == tyExpr and + idxt.sym != nil and idxt.sym.kind == skGenericParam: + let value = lookupTypeVar(cl, idxt).n + t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info) if containsGenericType(t): result = copyType(t, t.owner, false) incl(result.flags, tfFromGeneric) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 27c780391..a37b47366 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -626,7 +626,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyGenericParam, tyTypeClass: var x = PType(idTableGet(c.bindings, f)) if x == nil: - if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched: + if c.calleeSym != nil and c.calleeSym.kind == skType and + f.kind == tyGenericParam and not c.typedescMatched: # XXX: The fact that generic types currently use tyGenericParam for # their parameters is really a misnomer. tyGenericParam means "match # any value" and what we need is "match any type", which can be encoded @@ -670,7 +671,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation = result = isNone else: InternalAssert prev.sonsLen == 1 - result = typeRel(c, prev.sons[0], a) + let toMatch = if tfUnresolved in f.flags: a + else: a.sons[0] + result = typeRel(c, prev.sons[0], toMatch) of tyExpr, tyStmt: result = isGeneric of tyProxy: @@ -772,6 +775,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, if evaluated != nil: r = isGeneric arg.typ = newTypeS(tyExpr, c) + arg.typ.sons = @[evaluated.typ] arg.typ.n = evaluated if r == isGeneric: |