diff options
author | Zahary Karadjov <zahary@gmail.com> | 2013-12-25 19:25:04 +0200 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2013-12-25 19:25:04 +0200 |
commit | 1d02f2ea531ad14f686a75c30af9228ba84fa194 (patch) | |
tree | 086123d4040d4de250147ae0faae4bc1c5e4e325 | |
parent | 299cefdc984ef756ffb8dabb4e961a8d2505104f (diff) | |
download | Nim-1d02f2ea531ad14f686a75c30af9228ba84fa194.tar.gz |
wip type class reforms (the compiler bootstraps fine)
* replace tfAny and tfAll with tyAnd and tyOr * integrate matchTypeClass into typeRel * introduce tyBuiltInTypeClass to handle types such as tuple, object, proc, etc
-rw-r--r-- | compiler/ast.nim | 8 | ||||
-rw-r--r-- | compiler/msgs.nim | 2 | ||||
-rw-r--r-- | compiler/semdata.nim | 15 | ||||
-rw-r--r-- | compiler/semexprs.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 53 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 2 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 40 | ||||
-rw-r--r-- | compiler/types.nim | 71 |
8 files changed, 94 insertions, 99 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 462bad24f..64f959fe2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -339,6 +339,7 @@ type tyTypeClass tyParametricTypeClass # structured similarly to tyGenericInst # lastSon is the body of the type class + tyBuiltInTypeClass tyAnd tyOr tyNot @@ -349,7 +350,8 @@ const tyPureObject* = tyTuple GcTypeKinds* = {tyRef, tySequence, tyString} tyError* = tyProxy # as an errornous node should match everything - tyTypeClasses* = {tyTypeClass, tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything} + tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, + tyParametricTypeClass, tyAnd, tyOr, tyNot, tyAnything} type TTypeKinds* = set[TTypeKind] @@ -384,9 +386,6 @@ type # proc foo(T: typedesc, list: seq[T]): var T tfRetType, # marks return types in proc (used to detect type classes # used as return types for return type inference) - tfAll, # type class requires all constraints to be met (default) - tfAny, # type class requires any constraint to be met - tfNot, # type class with a negative check tfCapturesEnv, # whether proc really captures some environment tfByCopy, # pass object/tuple by copy (C backend) tfByRef, # pass object/tuple by reference (C backend) @@ -399,6 +398,7 @@ type tfHasShared, # type constains a "shared" constraint modifier somewhere tfHasMeta, # type has "typedesc" or "expr" somewhere; or uses '|' tfHasGCedMem, # type contains GC'ed memory + tfGenericTypeParam TTypeFlags* = set[TTypeFlag] diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 895ba71f3..9c24295a6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -643,6 +643,8 @@ proc toFileLine*(info: TLineInfo): string {.inline.} = proc toFileLineCol*(info: TLineInfo): string {.inline.} = result = info.toFilename & "(" & $info.line & "," & $info.col & ")" +template `$`*(info: TLineInfo): expr = toFileLineCol(info) + proc `??`* (info: TLineInfo, filename: string): bool = # only for debugging purposes result = filename in info.toFilename diff --git a/compiler/semdata.nim b/compiler/semdata.nim index d02359d4c..1984bfccb 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -213,6 +213,21 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc) return newSymNode(sym, info) +proc makeAndType*(c: PContext, t1, t2: PType): PType = + result = newTypeS(tyAnd, c) + result.sons = @[t1, t2] + result.flags.incl tfHasMeta + +proc makeOrType*(c: PContext, t1, t2: PType): PType = + result = newTypeS(tyOr, c) + result.sons = @[t1, t2] + result.flags.incl tfHasMeta + +proc makeNotType*(c: PContext, t1: PType): PType = + result = newTypeS(tyNot, c) + result.sons = @[t1] + result.flags.incl tfHasMeta + proc newTypeS(kind: TTypeKind, c: PContext): PType = result = newType(kind, getCurrOwner()) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 67373c303..fde09400d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1163,7 +1163,7 @@ proc semAsgn(c: PContext, n: PNode): PNode = if lhsIsResult: n.typ = EnforceVoidContext if lhs.sym.typ.kind == tyGenericParam: - if matchTypeClass(lhs.typ, rhs.typ): + if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric: InternalAssert c.p.resultSym != nil lhs.typ = rhs.typ c.p.resultSym.typ = rhs.typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 7e76e950b..17b7687b4 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -18,7 +18,7 @@ proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if result.kind == tyForward: result.kind = kind proc newConstraint(c: PContext, k: TTypeKind): PType = - result = newTypeS(tyTypeClass, c) + result = newTypeS(tyBuiltInTypeClass, c) result.addSonSkipIntLit(newTypeS(k, c)) proc semEnum(c: PContext, n: PNode, prev: PType): PType = @@ -603,6 +603,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType = let finalTypId = if typId != nil: typId else: getIdent(paramName & ":type") + if genericParams == nil: + # This happens with anonymous proc types appearing in signatures + # XXX: we need to lift these earlier + return # is this a bindOnce type class already present in the param list? for i in countup(0, genericParams.len - 1): if genericParams.sons[i].sym.name.id == finalTypId.id: @@ -674,7 +678,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, paramType.sons[i] = lifted result = paramType - if paramType.lastSon.kind == tyTypeClass: + if paramType.lastSon.kind == tyTypeClass and false: result = paramType result.kind = tyParametricTypeClass result = addImplicitGeneric(copyType(result, @@ -682,10 +686,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, elif result != nil: result.kind = tyGenericInvokation result.sons.setLen(result.sons.len - 1) - of tyTypeClass: + of tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), false)) of tyExpr: result = addImplicitGeneric(newTypeS(tyGenericParam, c)) + of tyGenericParam: + if tfGenericTypeParam in paramType.flags and false: + if paramType.sonsLen > 0: + result = liftingWalk(paramType.lastSon) + else: + result = addImplicitGeneric(newTypeS(tyGenericParam, c)) else: nil # result = liftingWalk(paramType) @@ -917,24 +927,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = var t1 = semTypeNode(c, n.sons[1], nil) t2 = semTypeNode(c, n.sons[2], nil) - if t1 == nil: + if t1 == nil: LocalError(n.sons[1].info, errTypeExpected) result = newOrPrevType(tyError, prev, c) - elif t2 == nil: + elif t2 == nil: LocalError(n.sons[2].info, errTypeExpected) result = newOrPrevType(tyError, prev, c) else: - result = newTypeS(tyTypeClass, c) - result.addSonSkipIntLit(t1) - result.addSonSkipIntLit(t2) - result.flags.incl(if op.id == ord(wAnd): tfAll else: tfAny) - result.flags.incl(tfHasMeta) + result = if op.id == ord(wAnd): makeAndType(c, t1, t2) + else: makeOrType(c, t1, t2) elif op.id == ord(wNot): - checkSonsLen(n, 3) - result = semTypeNode(c, n.sons[1], prev) - if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: - result = freshType(result, prev) - result.flags.incl(tfNotNil) + case n.len + of 3: + result = semTypeNode(c, n.sons[1], prev) + if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: + result = freshType(result, prev) + result.flags.incl(tfNotNil) + else: + LocalError(n.info, errGenerated, "invalid type") + of 2: + let negated = semTypeNode(c, n.sons[1], prev) + result = makeNotType(c, negated) else: LocalError(n.info, errGenerated, "invalid type") else: @@ -1088,11 +1101,7 @@ proc processMagicType(c: PContext, m: PSym) = else: LocalError(m.info, errTypeExpected) proc semGenericConstraints(c: PContext, x: PType): PType = - if x.kind in StructuralEquivTypes and ( - sonsLen(x) == 0 or x.sons[0].kind in {tyGenericParam, tyEmpty}): - result = newConstraint(c, x.kind) - else: - result = newTypeWithSons(c, tyGenericParam, @[x]) + result = newTypeWithSons(c, tyGenericParam, @[x]) proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) @@ -1127,7 +1136,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if typ == nil: typ = newTypeS(tyGenericParam, c) - + + typ.flags.incl tfGenericTypeParam + for j in countup(0, L-3): let finalType = if j == 0: typ else: copyType(typ, typ.owner, false) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index d05d063aa..f23d87763 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -19,7 +19,7 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) = proc checkConstructedType*(info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) - if t.kind in {tyTypeClass}: nil + if t.kind in tyTypeClasses: nil elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: LocalError(info, errInvalidPragmaX, "acyclic") elif t.kind == tyVar and t.sons[0].kind == tyVar: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 42eefec5a..03c37438c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -370,10 +370,6 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyNil: result = f.allowsNil else: nil -proc matchTypeClass(c: var TCandidate, f, a: PType): TTypeRelation = - result = if matchTypeClass(c.bindings, f, a): isGeneric - else: isNone - proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = let a0 = firstOrd(a) @@ -406,7 +402,7 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = # order to give preferrence to the most specific one: # # seq[seq[any]] is a strict subset of seq[any] and hence more specific. - + result = isNone assert(f != nil) assert(a != nil) @@ -462,10 +458,10 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = else: nil case f.kind - of tyEnum: + of tyEnum: if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype - of tyBool, tyChar: + of tyBool, tyChar: if a.kind == f.kind: result = isEqual elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype of tyRange: @@ -706,7 +702,20 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = return isGeneric else: return typeRel(c, prev, a) - + + of tyBuiltInTypeClass: + var prev = PType(idTableGet(c.bindings, f)) + if prev == nil: + let targetKind = f.sons[0].kind + if targetKind == a.skipTypes({tyRange}).kind or + (targetKind in {tyProc, tyPointer} and a.kind == tyNil): + put(c.bindings, f, a) + return isGeneric + else: + return isNone + else: + result = typeRel(c, prev, a) + of tyGenericParam, tyTypeClass: var x = PType(idTableGet(c.bindings, f)) if x == nil: @@ -727,11 +736,11 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = else: result = isNone else: - if a.kind == tyTypeClass: - result = isGeneric + if f.sonsLen > 0: + result = typeRel(c, f.lastSon, a) else: - result = matchTypeClass(c, f, a) - + result = isGeneric + if result == isGeneric: var concrete = concreteType(c, a) if concrete == nil: @@ -751,7 +760,7 @@ proc typeRel(c: var TCandidate, f, a: PType, doBind = true): TTypeRelation = if f.sonsLen == 0: result = isGeneric else: - result = matchTypeClass(c, f, a.sons[0]) + result = typeRel(c, f, a.sons[0]) if result == isGeneric: put(c.bindings, f, a) else: @@ -911,9 +920,8 @@ proc ParamTypesMatchAux(m: var TCandidate, f, argType: PType, InternalAssert a.len > 0 r = typeRel(m, f.lastSon, a.lastSon) else: - let match = matchTypeClass(m.bindings, fMaybeStatic, a) - if not match: r = isNone - else: + r = typeRel(m, fMaybeStatic, a) + if r != isNone: # XXX: Ideally, this should happen much earlier somewhere near # semOpAux, but to do that, we need to be able to query the # overload set to determine whether compile-time value is expected diff --git a/compiler/types.nim b/compiler/types.nim index 5fe128bbb..872834810 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -409,18 +409,8 @@ const "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", "!", "varargs[$1]", "iter[$1]", "Error Type", "TypeClass", - "ParametricTypeClass", "and", "or", "not", "any", "static"] - -proc consToStr(t: PType): string = - if t.len > 0: result = t.typeToString - else: result = typeToStr[t.kind].strip - -proc constraintsToStr(t: PType): string = - let sep = if tfAny in t.flags: " or " else: " and " - result = "" - for i in countup(0, t.len - 1): - if i > 0: result.add(sep) - result.add(t.sons[i].consToStr) + "ParametricTypeClass", "BuiltInTypeClass", + "and", "or", "not", "any", "static"] proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ @@ -444,19 +434,24 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = add(result, ']') of tyTypeDesc: if t.len == 0: result = "typedesc" - else: result = "typedesc[" & constraintsToStr(t) & "]" + else: result = "typedesc[" & typeToString(t) & "]" of tyStatic: InternalAssert t.len > 0 - result = "static[" & constraintsToStr(t) & "]" + result = "static[" & typeToString(t) & "]" of tyTypeClass: - if t.n != nil: return t.sym.owner.name.s - case t.len - of 0: result = "typeclass[]" - of 1: result = "typeclass[" & consToStr(t.sons[0]) & "]" - else: result = constraintsToStr(t) + InternalAssert t.sym != nil and t.sym.owner != nil + return t.sym.owner.name.s + of tyBuiltInTypeClass: + return "TypeClass" + of tyAnd: + result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) + of tyOr: + result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) + of tyNot: + result = "not " & typeToString(t.sons[0]) of tyExpr: if t.len == 0: result = "expr" - else: result = "expr[" & constraintsToStr(t) & "]" + else: result = "expr[" & typeToString(t) & "]" of tyArray: if t.sons[0].kind == tyRange: result = "array[" & rangeToStr(t.sons[0].n) & ", " & @@ -978,42 +973,6 @@ proc isGenericAlias*(t: PType): bool = proc skipGenericAlias*(t: PType): PType = return if t.isGenericAlias: t.lastSon else: t -proc matchTypeClass*(bindings: var TIdTable, typeClass, t: PType): bool = - for i in countup(0, typeClass.sonsLen - 1): - let req = typeClass.sons[i] - var match = req.kind == skipTypes(t, {tyRange, tyGenericInst}).kind - - if not match: - case req.kind - of tyGenericBody: - if t.kind == tyGenericInst and t.sons[0] == req: - match = true - IdTablePut(bindings, typeClass, t) - of tyTypeClass: - match = matchTypeClass(bindings, req, t) - elif t.kind == tyTypeClass: - match = matchTypeClass(bindings, t, req) - - elif t.kind in {tyObject} and req.len != 0: - # empty 'object' is fine as constraint in a type class - match = sameType(t, req) - - if tfAny in typeClass.flags: - if match: return true - else: - if not match: return false - - # if the loop finished without returning, either all constraints matched - # or none of them matched. - result = if tfAny in typeClass.flags: false else: true - if result == true: - IdTablePut(bindings, typeClass, t) - -proc matchTypeClass*(typeClass, typ: PType): bool = - var bindings: TIdTable - initIdTable(bindings) - result = matchTypeClass(bindings, typeClass, typ) - proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool = assert(kind in {skVar, skLet, skConst, skParam, skResult}) |