diff options
author | zah <zahary@gmail.com> | 2017-03-12 10:27:05 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-03-12 09:27:05 +0100 |
commit | 6e358e318747ecd6bea66911d6144cb7eff9d172 (patch) | |
tree | 74cb873c5eb65da8394f6d74e9e9c1a1b5148dc0 | |
parent | cb9d554ac93480c442a00129eaa0126396c884a3 (diff) | |
download | Nim-6e358e318747ecd6bea66911d6144cb7eff9d172.tar.gz |
don't allow casting to non-concrete types; fixes #5428 (#5502)
-rw-r--r-- | compiler/msgs.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 13 | ||||
-rw-r--r-- | compiler/types.nim | 1 | ||||
-rw-r--r-- | tests/errmsgs/tnon_concrete_cast.nim | 47 |
4 files changed, 58 insertions, 5 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e50ed0f2a..bf9090089 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -89,6 +89,7 @@ type errMainModuleMustBeSpecified, errXExpected, errTIsNotAConcreteType, + errCastToANonConcreteType, errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, @@ -326,6 +327,7 @@ const errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", errXExpected: "\'$1\' expected", errTIsNotAConcreteType: "\'$1\' is not a concrete type.", + errCastToANonConcreteType: "cannot cast to a non concrete type: \'$1\'", errInvalidSectionStart: "invalid section start", errGridTableNotImplemented: "grid table is not implemented", errGeneralParseError: "general parse error", diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a419cd000..755d44448 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -218,13 +218,16 @@ proc semConv(c: PContext, n: PNode): PNode = proc semCast(c: PContext, n: PNode): PNode = ## Semantically analyze a casting ("cast[type](param)") checkSonsLen(n, 2) + let targetType = semTypeNode(c, n.sons[0], nil) + let castedExpr = semExprWithType(c, n.sons[1]) + if tfHasMeta in targetType.flags: + localError(n.sons[0].info, errCastToANonConcreteType, $targetType) + if not isCastable(targetType, castedExpr.typ): + localError(n.info, errExprCannotBeCastToX, $targetType) result = newNodeI(nkCast, n.info) - result.typ = semTypeNode(c, n.sons[0], nil) + result.typ = targetType addSon(result, copyTree(n.sons[0])) - addSon(result, semExprWithType(c, n.sons[1])) - if not isCastable(result.typ, result.sons[1].typ): - localError(result.info, errExprCannotBeCastToX, - typeToString(result.typ)) + addSon(result, castedExpr) proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = const diff --git a/compiler/types.nim b/compiler/types.nim index df1d3e3ca..80fb6612d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -20,6 +20,7 @@ type preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string +template `$`*(typ: PType): string = typeToString(typ) proc base*(t: PType): PType = result = t.sons[0] diff --git a/tests/errmsgs/tnon_concrete_cast.nim b/tests/errmsgs/tnon_concrete_cast.nim new file mode 100644 index 000000000..e4ae890ce --- /dev/null +++ b/tests/errmsgs/tnon_concrete_cast.nim @@ -0,0 +1,47 @@ +discard """ + errormsg: "cannot cast to a non concrete type: 'ptr SomeNumber'" + line: 36 +""" + +# https://github.com/nim-lang/Nim/issues/5428 + +type + MemFile = object + mem: pointer + +proc memfileopen(filename: string, newFileSize: int): MemFile = + # just a memfile mock + return + +type + MyData = object + member1: seq[int] + member2: int + +type + MyReadWrite = object + memfile: MemFile + offset: int + +# Here, SomeNumber is bound to a concrete type, and that's OK +proc write(rw: var MyReadWrite; value: SomeNumber): void = + (cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + rw.offset.uint))[] = value + rw.offset += sizeof(SomeNumber) + +# Here, we try to use SomeNumber without binding it to a type. This should +# produce an error message for now. It's also possible to relax the rules +# and allow for type-class based type inference in such situations. +proc write[T](rw: var MyReadWrite; value: seq[T]): void = + rw.write value.len + let dst = cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + uint(rw.offset)) + let src = cast[pointer](value[0].unsafeAddr) + let size = sizeof(T) * value.len + copyMem(dst, src, size) + rw.offset += size + +proc saveBinFile(arg: var MyData, filename: string): void = + var rw: MyReadWrite + rw.memfile = memfileOpen(filename, newFileSize = rw.offset) + rw.offset = 0 + rw.write arg.member1 + |