diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-09-25 00:22:32 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-09-25 02:03:15 +0300 |
commit | badb6c0f665e22bff77d91bb2f64f195110b9887 (patch) | |
tree | 431c6d75d5619ce7df24f65b019944169b99b750 /compiler | |
parent | 92b0d640180c02489061eada2cb585f05e61eebc (diff) | |
download | Nim-badb6c0f665e22bff77d91bb2f64f195110b9887.tar.gz |
improved support for typedesc values
* can be stored in constants and variables (including in containers like sequences) * can be passed to and returned from macros
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 6 | ||||
-rwxr-xr-x | compiler/ccgstmts.nim | 1 | ||||
-rwxr-xr-x | compiler/ccgtypes.nim | 10 | ||||
-rwxr-xr-x | compiler/evals.nim | 8 | ||||
-rwxr-xr-x | compiler/procfind.nim | 3 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 5 | ||||
-rwxr-xr-x | compiler/seminst.nim | 39 | ||||
-rw-r--r-- | compiler/semmagic.nim | 8 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 24 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 5 | ||||
-rwxr-xr-x | compiler/types.nim | 60 |
11 files changed, 90 insertions, 79 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index e556ac671..814784029 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -344,6 +344,12 @@ type tfFromGeneric, # type is an instantiation of a generic; this is needed # because for instantiations of objects, structural # type equality has to be used + tfInstantiated # XXX: used to mark generic params after instantiation. + # if the concrete type happens to be an implicit generic + # this can lead to invalid proc signatures in the second + # pass of semProcTypeNode performed after instantiation. + # this won't be needed if we don't perform this redundant + # second pass (stay tuned). tfAll, # type class requires all constraints to be met (default) tfAny, # type class requires any constraint to be met tfCapturesEnv, # whether proc really captures some environment diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 9c25a44ec..9cb5d732b 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -163,6 +163,7 @@ proc genConstStmt(p: BProc, t: PNode) = if it.kind == nkCommentStmt: continue if it.kind != nkConstDef: InternalError(t.info, "genConstStmt") var c = it.sons[0].sym + if c.typ.containsCompileTimeOnly: continue if sfFakeConst in c.flags: genSingleVar(p, it) elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 054e7182e..0ab4ff200 100755 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -140,6 +140,14 @@ proc mangleName(s: PSym): PRope = proc isCompileTimeOnly(t: PType): bool = result = t.kind in {tyTypedesc, tyExpr} +proc containsCompileTimeOnly(t: PType): bool = + if isCompileTimeOnly(t): return true + if t.sons != nil: + for i in 0 .. <t.sonsLen: + if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]): + return true + return false + var anonTypeName = toRope"TY" proc typeName(typ: PType): PRope = @@ -174,7 +182,7 @@ proc mapType(typ: PType): TCTypeKind = of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray of tyObject, tyTuple: result = ctStruct of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, - tyConst, tyMutable, tyIter, tyTypeDesc: + tyConst, tyMutable, tyIter, tyTypeDesc: result = mapType(lastSon(typ)) of tyEnum: if firstOrd(typ) < 0: diff --git a/compiler/evals.nim b/compiler/evals.nim index 3f801e123..9c73a6b78 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -865,11 +865,11 @@ proc evalTypeTrait*(n: PNode, context: PSym): PNode = # 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 of "name": - result = newStrNode(nkStrLit, typ.typeToString(preferExported)) + result = newStrNode(nkStrLit, typ.typeToString(preferName)) result.typ = newType(tyString, context) result.info = n.info else: @@ -965,7 +965,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode = of mParseExprToAst: result = evalParseExpr(c, n) of mParseStmtToAst: result = evalParseStmt(c, n) of mExpandToAst: result = evalExpandToAst(c, n) - of mTypeTrait: result = evalTypeTrait(n, c.module) + of mTypeTrait: + n.sons[1] = evalAux(c, n.sons[1], {}) + result = evalTypeTrait(n, c.module) of mSlurp: result = evalSlurp(evalAux(c, n.sons[1], {}), c.module) of mStaticExec: let cmd = evalAux(c, n.sons[1], {}) diff --git a/compiler/procfind.nim b/compiler/procfind.nim index eefe734b3..fde4d22ea 100755 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -28,7 +28,8 @@ proc equalGenericParams(procA, procB: PNode): bool = return a = procA.sons[i].sym b = procB.sons[i].sym - if (a.name.id != b.name.id) or not sameTypeOrNil(a.typ, b.typ): return + if (a.name.id != b.name.id) or + not sameTypeOrNil(a.typ, b.typ, {TypeDescExactMatch}): return if (a.ast != nil) and (b.ast != nil): if not ExprStructuralEquivalent(a.ast, b.ast): return result = true diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a74907384..5dedc9b82 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -19,7 +19,8 @@ proc restoreOldStyleType(n: PNode) = # # This is strictly for backward compatibility until # the transition to types as first-class values is complete. - n.typ = n.typ.skipTypes({tyTypeDesc}) + if n.typ.kind == tyTypeDesc and n.typ.sonsLen == 1: + n.typ = n.typ.sons[0] proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = markUsed(n, s) @@ -376,6 +377,8 @@ proc semArrayConstr(c: PContext, n: PNode): PNode = addSon(result, semExprWithType(c, x)) var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal}) + # turn any concrete typedesc into the absract typedesc type + if typ.kind == tyTypeDesc: typ.sons = nil for i in countup(1, sonsLen(n) - 1): x = n.sons[i] if x.kind == nkExprColonExpr and sonsLen(x) == 2: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index ba950422f..61210c0f8 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -33,6 +33,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, #t = instGenericContainer(c, a, t) t = generateTypeInstance(c, pt, a, t) #t = ReplaceTypeVarsT(cl, t) + t.flags.incl tfInstantiated s.typ = t addDecl(c, s) entry.concreteTypes[i] = t @@ -41,7 +42,8 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool = if a.genericSym.id == b.genericSym.id and a.concreteTypes.len == b.concreteTypes.len: for i in 0 .. < a.concreteTypes.len: - if not sameType(a.concreteTypes[i], b.concreteTypes[i]): return + if not compareTypes(a.concreteTypes[i], b.concreteTypes[i], + flags = {TypeDescExactMatch}): return result = true proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym = @@ -122,33 +124,6 @@ proc sideEffectsCheck(c: PContext, s: PSym) = s.ast.sons[genericParamsPos].kind == nkEmpty: c.threadEntries.add(s) -proc applyConcreteTypesToSig(genericProc: PSym, concTypes: seq[PType]): PType = - # XXX: This is intended to replace the use of semParamList in generateInstance. - # The results of semParamList's analysis are already encoded in the original - # proc type and any concrete types may be aplied directly over it. - # Besides being more efficient, it will remove the awkward case of - # genericParams == nil in semParamList. - # Currenly, it fails in some cases such as: - # proc inc2*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.} - let sig = genericProc.typ - result = copyType(sig, getCurrOwner(), false) - result.n = sig.n.shallowCopy - - for i in countup(0, sig.len - 1): - let tOrig = sig.sons[i] - if tOrig == nil: continue - let oGenParams = genericProc.ast.sons[genericParamsPos] - if skipTypes(tOrig, skipPtrs).kind in {tyGenericParam}: - var tConcrete = concTypes[tOrig.sym.position] - if i > 0: - let param = sig.n.sons[i].sym.copySym - param.typ = tConcrete - result.n.sons[i] = newSymNode(param) - result.sons[i] = tConcrete - else: - result.sons[i] = tOrig - if i > 0: result.n.sons[i] = sig.n.sons[i] - proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym = # no need to instantiate generic templates/macros: @@ -182,12 +157,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, n.sons[genericParamsPos] = ast.emptyNode # semantic checking for the parameters: if n.sons[paramsPos].kind != nkEmpty: - if false and nimdbg: - result.typ = applyConcreteTypesToSig(fn, entry.concreteTypes) - addParams(c, result.typ.n, fn.kind) - else: - removeDefaultParamValues(n.sons[ParamsPos]) - semParamList(c, n.sons[ParamsPos], nil, result) + removeDefaultParamValues(n.sons[ParamsPos]) + semParamList(c, n.sons[ParamsPos], nil, result) else: result.typ = newTypeS(tyProc, c) rawAddSon(result.typ, nil) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index da179f0a7..119e1ef19 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -34,10 +34,14 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode = checkMinSonsLen(n, 2) internalAssert n.sons[1].kind == nkSym - if n.sons[1].sym.kind == skType: + let typArg = n.sons[1].sym + if typArg.kind == skType or + (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()) else: - # pass unmodified to evals + # a typedesc variable, pass unmodified to evals result = n proc semOrd(c: PContext, n: PNode): PNode = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 36b6a449d..5362d6d4a 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -552,7 +552,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = incl(result.flags, tfFinal) proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = - if kind == skMacro: + if kind == skMacro and param.typ.kind != tyTypeDesc: # within a macro, every param has the type PNimrodNode! # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: let nn = getSysSym"PNimrodNode" @@ -579,7 +579,8 @@ proc paramTypeClass(c: PContext, paramType: PType, procKind: TSymKind): result.typ = newTypeS(tyExpr, c) result.typ.sons = paramType.sons of tyTypeDesc: - if procKind notin {skTemplate, skMacro}: + if procKind notin {skTemplate, skMacro} and + tfInstantiated notin paramType.flags: result.typ = newTypeS(tyTypeDesc, c) result.typ.sons = paramType.sons of tyDistinct: @@ -777,19 +778,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = else: result = instGenericContainer(c, n, result) -proc semTypeFromMacro(c: PContext, n: PNode): PType = - # Expands a macro or template until a type is returned - # results in an error type if the macro expands to something different - var sym = expectMacroOrTemplateCall(c, n) - markUsed(n, sym) - case sym.kind - of skMacro: - result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil) - of skTemplate: - result = semTypeNode(c, semTemplateExpr(c, n, sym), nil) +proc semTypeExpr(c: PContext, n: PNode): PType = + var n = semExprWithType(c, n) + if n.kind == nkSym and n.sym.kind == skType: + result = n.sym.typ else: - LocalError(n.info, errXisNoMacroOrTemplate, n.renderTree) - result = errorType(c) + LocalError(n.info, errTypeExpected, n.renderTree) proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil @@ -823,7 +817,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result.addSonSkipIntLit(t2) result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) else: - result = semTypeFromMacro(c, n) + result = semTypeExpr(c, n) of nkCurlyExpr: result = semTypeNode(c, n.sons[0], nil) if result != nil: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 1d7b47bde..7e482b3d2 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -271,7 +271,7 @@ proc matchTypeClass(c: var TCandidate, typeClass, t: PType): TTypeRelation = of tyTypeClass: match = matchTypeClass(c, req, t) == isGeneric else: nil - elif t.kind in {tyTypeDesc, tyObject}: + elif t.kind in {tyObject}: match = sameType(t, req) if tfAny in typeClass.flags: @@ -659,7 +659,8 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, of isGeneric: inc(m.genericMatches) if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}: - result = argOrig + if f.kind == tyTypeDesc: result = arg + else: result = argOrig else: result = copyTree(arg) result.typ = getInstantiatedType(c, arg, m, f) diff --git a/compiler/types.nim b/compiler/types.nim index 5958914ba..d8879f1b4 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -585,10 +585,17 @@ type ## or a == (distinct b) dcEqOrDistinctOf ## a equals b or a is distinct of b + TTypeCmpFlag* = enum + IgnoreTupleFields, + TypeDescExactMatch, + AllowCommonBase + + TTypeCmpFlags* = set[TTypeCmpFlag] + TSameTypeClosure = object {.pure.} cmp: TDistinctCompare - ignoreTupleFields: bool recCheck: int + flags: TTypeCmpFlags s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster # (few elements expected) @@ -610,13 +617,14 @@ proc SameTypeOrNilAux(a, b: PType, c: var TSameTypeClosure): bool = if a == nil or b == nil: result = false else: result = SameTypeAux(a, b, c) -proc SameTypeOrNil*(a, b: PType): bool = +proc SameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool = if a == b: result = true else: if a == nil or b == nil: result = false else: var c = initSameTypeClosure() + c.flags = flags result = SameTypeAux(a, b, c) proc equalParam(a, b: PSym): TParamsEquality = @@ -655,7 +663,7 @@ proc equalParams(a, b: PNode): TParamsEquality = return paramsNotEqual # paramsIncompatible; # continue traversal! If not equal, we can return immediately; else # it stays incompatible - if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ): + if not SameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {TypeDescExactMatch}): if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): result = paramsNotEqual # one proc has a result, the other not is OK else: @@ -683,13 +691,13 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = for i in countup(0, sonsLen(a) - 1): var x = a.sons[i] var y = b.sons[i] - if c.ignoreTupleFields: + if IgnoreTupleFields in c.flags: x = skipTypes(x, {tyRange}) y = skipTypes(y, {tyRange}) result = SameTypeAux(x, y, c) if not result: return - if a.n != nil and b.n != nil and not c.ignoreTupleFields: + if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags: for i in countup(0, sonsLen(a.n) - 1): # check field names: if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym: @@ -760,7 +768,14 @@ proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool = if not SameObjectTree(a.n, b.n, c): return result = true -proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = +proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool = + if sonsLen(a) != sonsLen(b): return false + result = true + for i in countup(0, sonsLen(a) - 1): + result = SameTypeOrNilAux(a.sons[i], b.sons[i], c) + if not result: return + +proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = template CycleCheck() = # believe it or not, the direct check for ``containsOrIncl(c, a, b)`` # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat @@ -808,38 +823,43 @@ proc SameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = CycleCheck() result = sameTuple(a, b, c) of tyGenericInst: result = sameTypeAux(lastSon(a), lastSon(b), c) + of tyTypeDesc: + if TypeDescExactMatch in c.flags: + CycleCheck() + result = sameChildrenAux(x, y, c) + else: + result = true of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, - tyOrdinal, tyTypeDesc, tyTypeClass: - if sonsLen(a) == sonsLen(b): - CycleCheck() - result = true - for i in countup(0, sonsLen(a) - 1): - result = SameTypeOrNilAux(a.sons[i], b.sons[i], c) - if not result: return - if result and (a.kind == tyProc): - result = a.callConv == b.callConv + tyOrdinal, tyTypeClass: + CycleCheck() + result = sameChildrenAux(a, b, c) + if result and (a.kind == tyProc): + result = a.callConv == b.callConv of tyRange: - CycleCheck() + CycleCheck() result = SameTypeOrNilAux(a.sons[0], b.sons[0], c) and SameValue(a.n.sons[0], b.n.sons[0]) and SameValue(a.n.sons[1], b.n.sons[1]) of tyNone: result = false -proc SameType*(x, y: PType): bool = +proc sameType*(x, y: PType): bool = var c = initSameTypeClosure() result = sameTypeAux(x, y, c) - + proc sameBackendType*(x, y: PType): bool = var c = initSameTypeClosure() - c.ignoreTupleFields = true + c.flags.incl IgnoreTupleFields result = sameTypeAux(x, y, c) -proc compareTypes*(x, y: PType, cmp: TDistinctCompare): bool = +proc compareTypes*(x, y: PType, + cmp: TDistinctCompare = dcEq, + flags: TTypeCmpFlags = {}): bool = ## compares two type for equality (modulo type distinction) var c = initSameTypeClosure() c.cmp = cmp + c.flags = flags result = sameTypeAux(x, y, c) proc inheritanceDiff*(a, b: PType): int = |