Merge branch 'araq2' into devel

This commit is contained in:
Araq 2017-05-17 22:13:57 +02:00
commit 8f67b90997
54 changed files with 2479 additions and 340 deletions

View file

@ -730,7 +730,9 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
var s: PSym
if name.kind == nkDotExpr:
s = qualifiedLookUp(c, name, {checkUndeclared, checkModule})
if s.kind != skType or s.typ.skipTypes(abstractPtrs).kind != tyObject or tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
if s.kind != skType or
s.typ.skipTypes(abstractPtrs).kind != tyObject or
tfPartial notin s.typ.skipTypes(abstractPtrs).flags:
localError(name.info, "only .partial objects can be extended")
else:
s = semIdentDef(c, name, skType)
@ -742,6 +744,87 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
if sfGenSym notin s.flags: addInterfaceDecl(c, s)
a.sons[0] = newSymNode(s)
proc checkCovariantParamsUsages(genericType: PType) =
var body = genericType{-1}
proc traverseSubTypes(t: PType): bool =
template error(msg) = localError(genericType.sym.info, msg)
result = false
template subresult(r) =
let sub = r
result = result or sub
case t.kind
of tyGenericParam:
t.flags.incl tfWeakCovariant
return true
of tyObject:
for field in t.n:
subresult traverseSubTypes(field.typ)
of tyArray:
return traverseSubTypes(t[1])
of tyProc:
for subType in t.sons:
if subType != nil:
subresult traverseSubTypes(subType)
if result:
error("non-invariant type param used in a proc type: " & $t)
of tySequence:
return traverseSubTypes(t[0])
of tyGenericInvocation:
let targetBody = t[0]
for i in 1 .. <t.len:
let param = t[i]
if param.kind == tyGenericParam:
if tfCovariant in param.flags:
let formalFlags = targetBody[i-1].flags
if tfCovariant notin formalFlags:
error("covariant param '" & param.sym.name.s &
"' used in a non-covariant position")
elif tfWeakCovariant in formalFlags:
param.flags.incl tfWeakCovariant
result = true
elif tfContravariant in param.flags:
let formalParam = targetBody[i-1].sym
if tfContravariant notin formalParam.typ.flags:
error("contravariant param '" & param.sym.name.s &
"' used in a non-contravariant position")
result = true
else:
subresult traverseSubTypes(param)
of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass:
error("non-invariant type parameters cannot be used with types such '" & $t & "'")
of tyUserTypeClass, tyUserTypeClassInst:
error("non-invariant type parameters are not supported in concepts")
of tyTuple:
for fieldType in t.sons:
subresult traverseSubTypes(fieldType)
of tyPtr, tyRef, tyVar:
if t.base.kind == tyGenericParam: return true
return traverseSubTypes(t.base)
of tyDistinct, tyAlias:
return traverseSubTypes(t.lastSon)
of tyGenericInst:
internalAssert false
else:
discard
discard traverseSubTypes(body)
proc typeSectionRightSidePass(c: PContext, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
@ -782,6 +865,22 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
body.sym = s
body.size = -1 # could not be computed properly
s.typ.sons[sonsLen(s.typ) - 1] = body
if tfCovariant in s.typ.flags:
checkCovariantParamsUsages(s.typ)
# XXX: This is a temporary limitation:
# The codegen currently produces various failures with
# generic imported types that have fields, but we need
# the fields specified in order to detect weak covariance.
# The proper solution is to teach the codegen how to handle
# such types, because this would offer various interesting
# possibilities such as instantiating C++ generic types with
# garbage collected Nim types.
if sfImportc in s.flags:
var body = s.typ.lastSon
if body.kind == tyObject:
# erases all declared fields
body.n.sons = nil
popOwner(c)
closeScope(c)
elif a.sons[2].kind != nkEmpty:
@ -851,9 +950,12 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# type aliases are hard:
var t = semTypeNode(c, x, nil)
assert t != nil
if t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
if s.typ.kind != tyAlias:
if s.typ != nil and s.typ.kind != tyAlias:
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
assignType(s.typ, t)
s.typ.id = t.id
elif t.kind in {tyObject, tyEnum, tyDistinct}:
assert s.typ != nil
assignType(s.typ, t)
s.typ.id = t.id # same id
checkConstructedType(s.info, s.typ)
@ -1066,13 +1168,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner(c)
result.typ = s.typ
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
# 'do' without params produces a stmt:
if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
result = semStmt(c, n[bodyPos])
else:
result = semLambda(c, n, flags)
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n
@ -1177,7 +1272,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
var objB = t.sons[2]
while true:
if objB.kind == tyGenericBody: objB = objB.lastSon
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
objB = objB.sons[0]
else: break
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
if obj.assignment.isNil:
@ -1666,7 +1762,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: discard
if result.len == 1 and
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
# concept bodies should be preserved as a stmt list:
c.inTypeClass == 0 and
# also, don't make life complicated for macros.
# they will always expect a proper stmtlist:
nfBlockArg notin n.flags and
result.sons[0].kind != nkDefer:
result = result.sons[0]