diff options
author | Zahary Karadjov <zahary@gmail.com> | 2014-01-24 17:02:27 +0200 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2014-01-24 23:52:52 +0200 |
commit | 3f71b7f1f6db5fbe3c61dde0cfd43d1eb0088cb6 (patch) | |
tree | d5e96388da2ae2d57346ed11f89ac87f4eeafbcc /compiler | |
parent | a6a18be0899ff0445128c614f285be1924ec5281 (diff) | |
download | Nim-3f71b7f1f6db5fbe3c61dde0cfd43d1eb0088cb6.tar.gz |
implements #766;
expressions such as Type.field are now recognised by the compiler. This also fixes a bug, preventing the user-defined to check for the presence of regular fields in addition to procs
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 56 | ||||
-rw-r--r-- | compiler/ccgutils.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 14 | ||||
-rw-r--r-- | compiler/semfold.nim | 3 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 47 | ||||
-rw-r--r-- | compiler/transf.nim | 2 | ||||
-rw-r--r-- | compiler/types.nim | 52 | ||||
-rw-r--r-- | compiler/vm.nim | 2 |
11 files changed, 117 insertions, 69 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 4a3f1e894..7138b5f52 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -336,34 +336,52 @@ type tyConst, tyMutable, tyVarargs, tyIter, # unused tyProxy # used as errornous type (for idetools) - tyTypeClass - tyBuiltInTypeClass # Type such as the catch-all object, tuple, seq, etc - tyUserTypeClass - tyUserTypeClassInst # \ + + tyBuiltInTypeClass #\ + # Type such as the catch-all object, tuple, seq, etc + + tyUserTypeClass #\ + # the body of a user-defined type class + + tyUserTypeClassInst #\ # Instance of a parametric user-defined type class. # Structured similarly to tyGenericInst. # tyGenericInst represents concrete types, while # this is still a "generic param" that will bind types # and resolves them during sigmatch and instantiation. - tyCompositeTypeClass # Type such as seq[Number] - # The notes for tyUserTypeClassInst apply here as well - # sons[0]: the original expression used by the user. - # sons[1]: fully expanded and instantiated meta type - # (potentially following aliases) + tyCompositeTypeClass #\ + # Type such as seq[Number] + # The notes for tyUserTypeClassInst apply here as well + # sons[0]: the original expression used by the user. + # sons[1]: fully expanded and instantiated meta type + # (potentially following aliases) - tyAnd, tyOr, tyNot # boolean type classes such as `string|int`,`not seq`, - # `Sortable and Enumable`, etc + tyAnd, tyOr, tyNot #\ + # boolean type classes such as `string|int`,`not seq`, + # `Sortable and Enumable`, etc - tyAnything # a type class matching any type + tyAnything #\ + # a type class matching any type - tyStatic # a value known at compile type (the underlying type is .base) + tyStatic #\ + # a value known at compile type (the underlying type is .base) - tyFromExpr # This is a type representing an expression that depends - # on generic parameters (the exprsesion is stored in t.n) - # It will be converted to a real type only during generic - # instantiation and prior to this it has the potential to - # be any type. + tyFromExpr #\ + # This is a type representing an expression that depends + # on generic parameters (the exprsesion is stored in t.n) + # It will be converted to a real type only during generic + # instantiation and prior to this it has the potential to + # be any type. + + tyFieldAccessor #\ + # Expressions such as Type.field (valid in contexts such + # as the `is` operator and magics like `high` and `low`). + # Could be lifted to a single argument proc returning the + # field value. + # sons[0]: type of containing object or tuple + # sons[1]: field type + # .n: nkDotExpr storing the field name const tyPureObject* = tyTuple @@ -372,7 +390,7 @@ const tyUnknownTypes* = {tyError, tyFromExpr} - tyTypeClasses* = {tyTypeClass, tyBuiltInTypeClass, tyCompositeTypeClass, + tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyAnd, tyOr, tyNot, tyAnything} diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index fe349174f..1129ecbef 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -87,7 +87,7 @@ proc getUniqueType*(key: PType): PType = gCanonicalTypes[k] = key result = key of tyTypeDesc, tyTypeClasses, tyGenericParam, - tyFromExpr, tyStatic: + tyFromExpr, tyStatic, tyFieldAccessor: internalError("GetUniqueType") of tyGenericInst, tyDistinct, tyOrdinal, tyMutable, tyConst, tyIter: result = getUniqueType(lastSon(key)) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 82c45059c..c0fc4131a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -130,7 +130,7 @@ proc mapType(typ: PType): TJSTypeKind = result = etyObject of tyNil: result = etyNull of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, - tyNone, tyFromExpr, tyForward, tyEmpty, + tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: result = etyNone of tyProc: result = etyProc diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 37fdf8b34..1096d3029 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -239,7 +239,8 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = localError(n.info, errXExpectsTypeOrValue, opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) - var typ = skipTypes(n.sons[1].typ, abstractVarRange+{tyTypeDesc}) + var typ = skipTypes(n.sons[1].typ, abstractVarRange + + {tyTypeDesc, tyFieldAccessor}) case typ.kind of tySequence, tyString, tyOpenArray, tyVarargs: n.typ = getSysType(tyInt) @@ -247,7 +248,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = n.typ = typ.sons[0] # indextype of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: # do not skip the range! - n.typ = n.sons[1].typ.skipTypes(abstractVar) + n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor}) of tyGenericParam: # prepare this for resolving in semtypinst: # we must use copyTree here in order to avoid creating a cycle @@ -306,7 +307,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - let t1 = n[1].typ.skipTypes({tyTypeDesc}) + let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor}) if n[2].kind in {nkStrLit..nkTripleStrLit}: case n[2].strVal.normalize @@ -948,6 +949,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = let foundTyp = makeTypeDesc(c, rawTyp) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) return + of tyObject, tyTuple: + if ty.n.kind == nkRecList: + for field in ty.n.sons: + if field.sym.name == i: + n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) + n.typ.n = copyTree(n) + return n else: # echo "TYPE FIELD ACCESS" # debug ty diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 78e5cdd5e..4740ddcb3 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -252,8 +252,7 @@ proc evalIs(n, a: PNode): PNode = else: # XXX semexprs.isOpImpl is slightly different and requires a context. yay. let t2 = n[2].typ - var match = if t2.kind == tyTypeClass: true - else: sameType(t1, t2) + var match = sameType(t1, t2) result = newIntNode(nkIntLit, ord(match)) result.typ = n.typ diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index fc1706200..d28eaa779 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1240,7 +1240,7 @@ proc semStmtList(c: PContext, n: PNode): PNode = if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]): voidContext = true n.typ = enforceVoidContext - if i != last or voidContext: + if i != last or voidContext or c.inTypeClass > 0: discardCheck(c, n.sons[i]) else: n.typ = n.sons[i].typ diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4bcaf55d6..408b1b62e 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -736,7 +736,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, allowMetaTypes = true) result = liftingWalk(expanded) - of tyUserTypeClass, tyTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: + of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) of tyExpr: @@ -871,7 +871,7 @@ proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = result = newOrPrevType(tyGenericInvokation, prev, c) addSonSkipIntLit(result, s.typ) - + template addToResult(typ) = if typ.isNil: internalAssert false diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d0a832147..971d526ee 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -140,7 +140,7 @@ proc sumGeneric(t: PType): int = result = ord(t.kind == tyGenericInvokation) for i in 0 .. <t.len: result += t.sons[i].sumGeneric break - of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc, tyTypeClass: break + of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break else: return 0 proc complexDisambiguation(a, b: PType): int = @@ -447,18 +447,19 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, dummyParam.typ = dummyType addDecl(c, dummyParam) - for stmt in body.n[3]: - var e = c.semTryExpr(c, copyTree(stmt), bufferErrors = false) - m.errors = bufferedMsgs - clearBufferedMsgs() - if e == nil: return isNone - - case e.kind - of nkReturnStmt: discard - of nkTypeSection: discard - of nkConstDef: discard - else: discard - + var checkedBody = c.semTryExpr(c, copyTree(body.n[3]), bufferErrors = false) + m.errors = bufferedMsgs + clearBufferedMsgs() + if checkedBody == nil: return isNone + + if checkedBody.kind == nkStmtList: + for stmt in checkedBody: + case stmt.kind + of nkReturnStmt: discard + of nkTypeSection: discard + of nkConstDef: discard + else: discard + return isGeneric # put(m.bindings, f, a) @@ -481,6 +482,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isNone assert(f != nil) + + if f.kind == tyExpr: + put(c.bindings, f, aOrig) + return isGeneric + assert(aOrig != nil) # var and static arguments match regular modifier-free types @@ -828,7 +834,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: return isNone - of tyGenericParam, tyTypeClass: + of tyGenericParam: var x = PType(idTableGet(c.bindings, f)) if x == nil: if c.calleeSym != nil and c.calleeSym.kind == skType and @@ -891,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = else: a.sons[0] result = typeRel(c, prev.sons[0], toMatch) - of tyExpr, tyStmt: + of tyStmt: result = isGeneric of tyProxy: @@ -993,20 +999,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argType = arg.typ var - r: TTypeRelation a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc}) else: argType - case fMaybeStatic.kind - of tyTypeClass: - if fMaybeStatic.n != nil: - r = matchUserTypeClass(c, m, fMaybeStatic, a) - else: - r = typeRel(m, f, a) - of tyExpr: - r = isGeneric - put(m.bindings, f, arg.typ) - else: r = typeRel(m, f, a) case r diff --git a/compiler/transf.nim b/compiler/transf.nim index f22433972..b00e0a143 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -389,7 +389,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result[0] = transform(c, n.sons[1]) else: result = transform(c, n.sons[1]) - of tyGenericParam, tyOrdinal, tyTypeClass: + of tyGenericParam, tyOrdinal: result = transform(c, n.sons[1]) # happens sometimes for generated assignments, etc. else: diff --git a/compiler/types.nim b/compiler/types.nim index cc066a36d..4a53a84c9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -405,9 +405,9 @@ const "uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", "!", "varargs[$1]", "iter[$1]", "Error Type", - "TypeClass", "BuiltInTypeClass", "UserTypeClass", + "BuiltInTypeClass", "UserTypeClass", "UserTypeClassInst", "CompositeTypeClass", - "and", "or", "not", "any", "static", "TypeFromExpr"] + "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"] proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = var t = typ @@ -435,11 +435,30 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyStatic: internalAssert t.len > 0 result = "static[" & typeToString(t.sons[0]) & "]" - of tyTypeClass: + of tyUserTypeClass: internalAssert t.sym != nil and t.sym.owner != nil return t.sym.owner.name.s of tyBuiltInTypeClass: - return "TypeClass" + result = case t.base.kind: + of tyVar: "var" + of tyRef: "ref" + of tyPtr: "ptr" + of tySequence: "seq" + of tyArray: "array" + of tySet: "set" + of tyRange: "range" + of tyDistinct: "distinct" + of tyProc: "proc" + of tyObject: "object" + of tyTuple: "tuple" + else: (internalAssert false; "") + of tyUserTypeClassInst: + let body = t.base + result = body.sym.name.s & "[" + for i in countup(1, sonsLen(t) - 2): + if i > 1: add(result, ", ") + add(result, typeToString(t.sons[i])) + result.add "]" of tyAnd: result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1]) of tyOr: @@ -449,7 +468,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = of tyExpr: internalAssert t.len == 0 result = "expr" - of tyFromExpr: + of tyFromExpr, tyFieldAccessor: result = renderTree(t.n) of tyArray: if t.sons[0].kind == tyRange: @@ -547,7 +566,8 @@ proc firstOrd(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc: + of tyGenericInst, tyDistinct, tyConst, tyMutable, + tyTypeDesc, tyFieldAccessor: result = firstOrd(lastSon(t)) else: internalError("invalid kind for first(" & $t.kind & ')') @@ -580,7 +600,8 @@ proc lastOrd(t: PType): BiggestInt = of tyEnum: assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) result = t.n.sons[sonsLen(t.n) - 1].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc: + of tyGenericInst, tyDistinct, tyConst, tyMutable, + tyTypeDesc, tyFieldAccessor: result = lastOrd(lastSon(t)) of tyProxy: result = 0 else: @@ -876,9 +897,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = of tyGenericInvokation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, - tyOrdinal, tyTypeClasses: + tyOrdinal, tyTypeClasses, tyFieldAccessor: cycleCheck() - if a.kind == tyTypeClass and a.n != nil: return a.n == b.n + if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and a.kind == tyProc: result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and @@ -1022,7 +1043,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, of tyTypeClasses: result = true of tyGenericBody, tyGenericParam, tyGenericInvokation, - tyNone, tyForward, tyFromExpr: + tyNone, tyForward, tyFromExpr, tyFieldAccessor: result = false of tyNil: result = kind == skConst @@ -1232,8 +1253,15 @@ proc getSize(typ: PType): BiggestInt = if result < 0: internalError("getSize: " & $typ.kind) proc containsGenericTypeIter(t: PType, closure: PObject): bool = - result = t.kind in GenericTypes + tyTypeClasses + {tyTypeDesc,tyFromExpr} or - t.kind == tyStatic and t.n == nil + if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}: + return true + + if t.kind == tyTypeDesc: + if t.sonsLen == 0: return true + if containsGenericTypeIter(t.base, closure): return true + return false + + return t.kind == tyStatic and t.n == nil proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) diff --git a/compiler/vm.nim b/compiler/vm.nim index 9ed18d29e..cd36595ac 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -802,7 +802,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = let t1 = regs[rb].typ.skipTypes({tyTypeDesc}) let t2 = c.types[regs[rc].intVal.int] # XXX: This should use the standard isOpImpl - let match = if t2.kind == tyTypeClass: true + let match = if t2.kind == tyUserTypeClass: true else: sameType(t1, t2) regs[ra].intVal = ord(match) of opcSetLenSeq: |