summary refs log tree commit diff stats
path: root/compiler/semexprs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semexprs.nim')
-rwxr-xr-xcompiler/semexprs.nim98
1 files changed, 59 insertions, 39 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 2c98d9de6..2b39f6190 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -125,44 +125,48 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   else:
     markUsed(n, s)
     result = newSymNode(s, n.info)
-  
-proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
-  var diff = inheritanceDiff(castDest, src)
-  if diff == high(int):
-    LocalError(info, errGenerated, MsgKindToString(errIllegalConvFromXtoY) % [
-        src.typeToString, castDest.typeToString])
+
+type
+  TConvStatus = enum
+    convOK,
+    convNotNeedeed,
+    convNotLegal
+
+proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
+  return if inheritanceDiff(castDest, src) == high(int):
+      convNotLegal
+    else:
+      convOK
 
 const 
   IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
 
-proc checkConvertible(info: TLineInfo, castDest, src: PType) = 
-  if sameType(castDest, src) and castDest.sym == src.sym: 
+proc checkConvertible(castDest, src: PType): TConvStatus =
+  result = convOK
+  if sameType(castDest, src) and castDest.sym == src.sym:
     # don't annoy conversions that may be needed on another processor:
     if castDest.kind notin IntegralTypes+{tyRange}:
-      Message(info, hintConvFromXtoItselfNotNeeded, typeToString(castDest))
+      result = convNotNeedeed
     return
   var d = skipTypes(castDest, abstractVar)
   var s = skipTypes(src, abstractVar)
-  while (d != nil) and (d.Kind in {tyPtr, tyRef}) and (d.Kind == s.Kind): 
+  while (d != nil) and (d.Kind in {tyPtr, tyRef}) and (d.Kind == s.Kind):
     d = base(d)
     s = base(s)
   if d == nil:
-    LocalError(info, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
-        src.typeToString, castDest.typeToString])
-  elif d.Kind == tyObject and s.Kind == tyObject: 
-    checkConversionBetweenObjects(info, d, s)
+    result = convNotLegal
+  elif d.Kind == tyObject and s.Kind == tyObject:
+    result = checkConversionBetweenObjects(d, s)
   elif (skipTypes(castDest, abstractVarRange).Kind in IntegralTypes) and
-      (skipTypes(src, abstractVarRange).Kind in IntegralTypes): 
+      (skipTypes(src, abstractVarRange).Kind in IntegralTypes):
     # accept conversion between integral types
-  else: 
+  else:
     # we use d, s here to speed up that operation a bit:
     case cmpTypes(d, s)
-    of isNone, isGeneric: 
+    of isNone, isGeneric:
       if not compareTypes(castDest, src, dcEqIgnoreDistinct):
-        LocalError(info, errGenerated, `%`(
-            MsgKindToString(errIllegalConvFromXtoY), 
-            [typeToString(src), typeToString(castDest)]))
-    else: 
+        result = convNotLegal
+    else:
       nil
 
 proc isCastable(dst, src: PType): bool = 
@@ -184,23 +188,32 @@ proc isCastable(dst, src: PType): bool =
         (skipTypes(src, abstractInst).kind in IntegralTypes)
   
 proc isSymChoice(n: PNode): bool {.inline.} =
-  result = n.kind in {nkClosedSymChoice, nkOpenSymChoice}
+  result = n.kind in nkSymChoices
 
-proc semConv(c: PContext, n: PNode, s: PSym): PNode = 
-  if sonsLen(n) != 2: 
+proc semConv(c: PContext, n: PNode, s: PSym): PNode =
+  if sonsLen(n) != 2:
     LocalError(n.info, errConvNeedsOneArg)
     return n
   result = newNodeI(nkConv, n.info)
-  result.typ = semTypeNode(c, n.sons[0], nil)
+  result.typ = semTypeNode(c, n.sons[0], nil).skipTypes({tyGenericInst})
   addSon(result, copyTree(n.sons[0]))
   addSon(result, semExprWithType(c, n.sons[1]))
   var op = result.sons[1]
+     
   if not isSymChoice(op):
-    checkConvertible(result.info, result.typ, op.typ)
-  else: 
+    let status = checkConvertible(result.typ, op.typ)
+    case status
+    of convOK: nil
+    of convNotNeedeed:
+      Message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
+    of convNotLegal:
+      LocalError(n.info, errGenerated, MsgKindToString(errIllegalConvFromXtoY)%
+        [op.typ.typeToString, result.typ.typeToString])
+  else:
     for i in countup(0, sonsLen(op) - 1):
       let it = op.sons[i]
-      if sameType(result.typ, it.typ): 
+      let status = checkConvertible(result.typ, it.typ)
+      if status == convOK:
         markUsed(n, it.sym)
         markIndirect(c, it.sym)
         return it
@@ -492,12 +505,16 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
     result = newHiddenAddrTaken(c, n) # BUGFIX!
   
 proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = 
+  checkMinSonsLen(n, 1)
   const 
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, 
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, 
       mAppendSeqElem, mNewSeq, mReset, mShallowCopy}
-  checkMinSonsLen(n, 1)
-  var t = n.sons[0].typ
+  
+  # get the real type of the callee
+  # it may be a proc var with a generic alias type, so we skip over them
+  var t = n.sons[0].typ.skipTypes({tyGenericInst})
+
   if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams: 
     # BUGFIX: check for L-Value still needs to be done for the arguments!
     for i in countup(1, sonsLen(n) - 1): 
@@ -618,7 +635,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   semOpAux(c, n)
   var t: PType = nil
   if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst)
-  if (t != nil) and (t.kind == tyProc): 
+  if (t != nil) and (t.kind == tyProc):
+    # This is a proc variable, apply normal overload resolution
     var m: TCandidate
     initCandidate(m, t)
     matches(c, n, nOrig, m)
@@ -648,6 +666,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # we assume that a procedure that calls something indirectly 
     # has side-effects:
     if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
+  elif (t != nil) and t.kind == tyTypeDesc:
+    let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
+    result = semConv(c, n, symFromType(destType, n.info))
+    return 
   else:
     result = overloadedCallOpr(c, n)
     # Now that nkSym does not imply an iteration over the proc/iterator space,
@@ -956,10 +978,10 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result.typ = elemType(arr)
     #GlobalError(n.info, errIndexTypesDoNotMatch)
   of tyTypeDesc:
-    result = n.sons[0] # The result so far is a tyTypeDesc bound to
-                       # a tyGenericBody. The line below will substitute
-                       # it with the instantiated type.
-    result.typ.sons[0] = semTypeNode(c, n, nil).linkTo(result.sym)
+    # The result so far is a tyTypeDesc bound 
+    # a tyGenericBody. The line below will substitute
+    # it with the instantiated type.
+    result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
   of tyTuple: 
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
@@ -1715,12 +1737,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkTableConstr:
     result = semTableConstr(c, n)
   of nkClosedSymChoice, nkOpenSymChoice:
-    LocalError(n.info, errExprXAmbiguous, renderTree(n, {renderNoComments}))
-    # error correction: Pick first element:
-    result = n.sons[0]
+    # handling of sym choices is context dependent
+    # the node is left intact for now
   of nkStaticExpr:
     result = semStaticExpr(c, n)
-
   of nkAsgn: result = semAsgn(c, n)
   of nkBlockStmt: result = semBlock(c, n)
   of nkStmtList: result = semStmtList(c, n)