summary refs log tree commit diff stats
path: root/compiler/semexprs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semexprs.nim')
-rw-r--r--compiler/semexprs.nim342
1 files changed, 220 insertions, 122 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index b47aff429..84d45b7df 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -26,7 +26,7 @@ const
   errUndeclaredFieldX = "undeclared field: '$1'"
 
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
-                     flags: TExprFlags = {}): PNode =
+                     flags: TExprFlags = {}; expectedType: PType = nil): PNode =
   rememberExpansion(c, n.info, s)
   let info = getCallLineInfo(n)
   markUsed(c, info, s)
@@ -36,7 +36,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
   pushInfoContext(c.config, n.info, s.detailedInfo)
   result = evalTemplate(n, s, getCurrOwner(c), c.config, c.cache,
                         c.templInstCounter, c.idgen, efFromHlo in flags)
-  if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
+  if efNoSemCheck notin flags:
+    result = semAfterMacroCall(c, n, result, s, flags, expectedType)
   popInfoContext(c.config)
 
   # XXX: A more elaborate line info rewrite might be needed
@@ -65,9 +66,9 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
 
-proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType = nil): PNode =
   rejectEmptyNode(n)
-  result = semExpr(c, n, flags+{efWantValue})
+  result = semExpr(c, n, flags+{efWantValue}, expectedType)
 
   let
     isEmpty = result.kind == nkEmpty
@@ -82,8 +83,8 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags): PNode =
     # do not produce another redundant error message:
     result = errorNode(c, n)
 
-proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
-  result = semExprCheck(c, n, flags)
+proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
+  result = semExprCheck(c, n, flags, expectedType)
   if result.typ == nil and efInTypeof in flags:
     result.typ = c.voidType
   elif result.typ == nil or result.typ == c.enforceVoidContext:
@@ -261,7 +262,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool =
   let s = qualifiedLookUp(c, n, {})
   result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
 
-proc semConv(c: PContext, n: PNode): PNode =
+proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   if n.len != 2:
     localError(c.config, n.info, "a type conversion takes exactly one argument")
     return n
@@ -277,7 +278,7 @@ proc semConv(c: PContext, n: PNode): PNode =
     else:
       targetType = targetType.base
   of tyStatic:
-    var evaluated = semStaticExpr(c, n[1])
+    var evaluated = semStaticExpr(c, n[1], expectedType)
     if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
       result = n
       result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
@@ -583,21 +584,36 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
   typ[0] = makeRangeType(c, 0, n.len - 1, n.info)
   result = typ
 
-proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = newNodeI(nkBracket, n.info)
   result.typ = newTypeS(tyArray, c)
+  var expectedElementType, expectedIndexType: PType = nil
+  if expectedType != nil:
+    let expected = expectedType.skipTypes(abstractRange-{tyDistinct})
+    case expected.kind
+    of tyArray:
+      expectedIndexType = expected[0]
+      expectedElementType = expected[1]
+    of tyOpenArray:
+      expectedElementType = expected[0]
+    else: discard
   rawAddSon(result.typ, nil)     # index type
   var
     firstIndex, lastIndex: Int128
     indexType = getSysType(c.graph, n.info, tyInt)
     lastValidIndex = lastOrd(c.config, indexType)
   if n.len == 0:
-    rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
+    rawAddSon(result.typ,
+      if expectedElementType != nil and
+          typeAllowed(expectedElementType, skLet, c) == nil:
+        expectedElementType
+      else:
+        newTypeS(tyEmpty, c)) # needs an empty basetype!
     lastIndex = toInt128(-1)
   else:
     var x = n[0]
     if x.kind == nkExprColonExpr and x.len == 2:
-      var idx = semConstExpr(c, x[0])
+      var idx = semConstExpr(c, x[0], expectedIndexType)
       if not isOrdinalType(idx.typ):
         localError(c.config, idx.info, "expected ordinal value for array " &
                    "index, got '$1'" % renderTree(idx))
@@ -608,8 +624,10 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
         lastValidIndex = lastOrd(c.config, indexType)
         x = x[1]
 
-    let yy = semExprWithType(c, x)
+    let yy = semExprWithType(c, x, expectedType = expectedElementType)
     var typ = yy.typ
+    if expectedElementType == nil:
+      expectedElementType = typ
     result.add yy
     #var typ = skipTypes(result[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
     for i in 1..<n.len:
@@ -621,13 +639,13 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
 
       x = n[i]
       if x.kind == nkExprColonExpr and x.len == 2:
-        var idx = semConstExpr(c, x[0])
+        var idx = semConstExpr(c, x[0], indexType)
         idx = fitNode(c, indexType, idx, x.info)
         if lastIndex+1 != getOrdValue(idx):
           localError(c.config, x.info, "invalid order in array constructor")
         x = x[1]
 
-      let xx = semExprWithType(c, x, {})
+      let xx = semExprWithType(c, x, {}, expectedElementType)
       result.add xx
       typ = commonType(c, typ, xx.typ)
       #n[i] = semExprWithType(c, x, {})
@@ -853,10 +871,10 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     #if result != n:
     #  echo "SUCCESS evaluated at compile time: ", call.renderTree
 
-proc semStaticExpr(c: PContext, n: PNode): PNode =
+proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   inc c.inStaticContext
   openScope(c)
-  let a = semExprWithType(c, n)
+  let a = semExprWithType(c, n, expectedType = expectedType)
   closeScope(c)
   dec c.inStaticContext
   if a.findUnresolvedStatic != nil: return a
@@ -900,7 +918,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
           rawAddSon(typ, result.typ)
           result.typ = typ
 
-proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
+proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
 
 proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
                          t: PType): TCandidate =
@@ -923,15 +941,15 @@ proc setGenericParams(c: PContext, n: PNode) =
   for i in 1..<n.len:
     n[i].typ = semTypeNode(c, n[i], nil)
 
-proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
+proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
     return errorNode(c, n)
 
   result = n
   let callee = result[0].sym
   case callee.kind
-  of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
-  of skTemplate: result = semTemplateExpr(c, result, callee, flags)
+  of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
+  of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
   else:
     semFinishOperands(c, result)
     activate(c, result)
@@ -947,7 +965,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
   if c.matchedConcept == nil:
     result = evalAtCompileTime(c, result)
 
-proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = nil
   checkMinSonsLen(n, 1, c.config)
   var prc = n[0]
@@ -972,13 +990,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       let s = bracketedMacro(n[0])
       if s != nil:
         setGenericParams(c, n[0])
-        return semDirectOp(c, n, flags)
+        return semDirectOp(c, n, flags, expectedType)
 
-  let nOrig = n.copyTree
-  semOpAux(c, n)
   var t: PType = nil
   if n[0].typ != nil:
     t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
+  if t != nil and t.kind == tyTypeDesc:
+    if n.len == 1: return semObjConstr(c, n, flags, expectedType)
+    return semConv(c, n)
+
+  let nOrig = n.copyTree
+  semOpAux(c, n)
   if t != nil and t.kind == tyProc:
     # This is a proc variable, apply normal overload resolution
     let m = resolveIndirectCall(c, n, nOrig, t)
@@ -1017,9 +1039,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result = m.call
       instGenericConvertersSons(c, result, m)
 
-  elif t != nil and t.kind == tyTypeDesc:
-    if n.len == 1: return semObjConstr(c, n, flags)
-    return semConv(c, n)
   else:
     result = overloadedCallOpr(c, n)
     # Now that nkSym does not imply an iteration over the proc/iterator space,
@@ -1038,17 +1057,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       return result
   #result = afterCallActions(c, result, nOrig, flags)
   if result[0].kind == nkSym:
-    result = afterCallActions(c, result, nOrig, flags)
+    result = afterCallActions(c, result, nOrig, flags, expectedType)
   else:
     fixAbstractType(c, result)
     analyseIfAddressTakenInCall(c, result)
 
-proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   # this seems to be a hotspot in the compiler!
   let nOrig = n.copyTree
   #semLazyOpAux(c, n)
   result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
-  if result != nil: result = afterCallActions(c, result, nOrig, flags)
+  if result != nil: result = afterCallActions(c, result, nOrig, flags, expectedType)
   else: result = errorNode(c, n)
 
 proc buildEchoStmt(c: PContext, n: PNode): PNode =
@@ -1594,11 +1613,11 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else:
         discard
 
-proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = semSubscript(c, n, flags)
   if result == nil:
     # overloaded [] operator:
-    result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags)
+    result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "[]")), flags, expectedType)
 
 proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
   var id = considerQuotedIdent(c, a[1], a)
@@ -1774,7 +1793,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
                renderTree(a, {renderNoComments}))
   else:
     let lhs = n[0]
-    let rhs = semExprWithType(c, n[1], {})
+    let rhs = semExprWithType(c, n[1], {}, le)
     if lhs.kind == nkSym and lhs.sym.kind == skResult:
       n.typ = c.enforceVoidContext
       if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
@@ -1823,9 +1842,9 @@ proc semReturn(c: PContext, n: PNode): PNode =
   else:
     localError(c.config, n.info, "'return' not allowed here")
 
-proc semProcBody(c: PContext, n: PNode): PNode =
+proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   openScope(c)
-  result = semExpr(c, n)
+  result = semExpr(c, n, expectedType = expectedType)
   if c.p.resultSym != nil and not isEmptyType(result.typ):
     if result.kind == nkNilLit:
       # or ImplicitlyDiscardable(result):
@@ -2256,7 +2275,7 @@ proc semSizeof(c: PContext, n: PNode): PNode =
   n.typ = getSysType(c.graph, n.info, tyInt)
   result = foldSizeOf(c.config, n, n)
 
-proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
+proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
   # this is a hotspot in the compiler!
   result = n
   case s.magic # magics that need special treatment
@@ -2372,8 +2391,17 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mSizeOf:
     markUsed(c, n.info, s)
     result = semSizeof(c, setMs(n, s))
+  of mArrToSeq, mOpenArrayToSeq:
+    if n.len == 2 and expectedType != nil and (
+        let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+        expected.kind in {tySequence, tyOpenArray}):
+      # seq type inference
+      var arrayType = newType(tyOpenArray, nextTypeId(c.idgen), expected.owner)
+      arrayType.rawAddSon(expected[0])
+      n[1] = semExpr(c, n[1], flags, arrayType)
+    result = semDirectOp(c, n, flags, expectedType)
   else:
-    result = semDirectOp(c, n, flags)
+    result = semDirectOp(c, n, flags, expectedType)
 
 proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   # If semCheck is set to false, ``when`` will return the verbatim AST of
@@ -2432,33 +2460,49 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
     result = newNodeI(nkEmpty, n.info)
   if whenNimvm: result.typ = typ
 
-proc semSetConstr(c: PContext, n: PNode): PNode =
+proc semSetConstr(c: PContext, n: PNode, expectedType: PType = nil): PNode =
   result = newNodeI(nkCurly, n.info)
   result.typ = newTypeS(tySet, c)
   result.typ.flags.incl tfIsConstructor
+  var expectedElementType: PType = nil
+  if expectedType != nil and (
+      let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+      expected.kind == tySet):
+    expectedElementType = expected[0]
   if n.len == 0:
-    rawAddSon(result.typ, newTypeS(tyEmpty, c))
+    rawAddSon(result.typ,
+      if expectedElementType != nil and
+          typeAllowed(expectedElementType, skLet, c) == nil:
+        expectedElementType
+      else:
+        newTypeS(tyEmpty, c))
   else:
     # only semantic checking for all elements, later type checking:
     var typ: PType = nil
     for i in 0..<n.len:
       if isRange(n[i]):
         checkSonsLen(n[i], 3, c.config)
-        n[i][1] = semExprWithType(c, n[i][1])
-        n[i][2] = semExprWithType(c, n[i][2])
+        n[i][1] = semExprWithType(c, n[i][1], {}, expectedElementType)
+        n[i][2] = semExprWithType(c, n[i][2], {}, expectedElementType)
         if typ == nil:
           typ = skipTypes(n[i][1].typ,
                           {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
+          if expectedElementType == nil:
+            expectedElementType = typ
         n[i].typ = n[i][2].typ # range node needs type too
       elif n[i].kind == nkRange:
         # already semchecked
         if typ == nil:
           typ = skipTypes(n[i][0].typ,
                           {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
+          if expectedElementType == nil:
+            expectedElementType = typ
       else:
-        n[i] = semExprWithType(c, n[i])
+        n[i] = semExprWithType(c, n[i], {}, expectedElementType)
         if typ == nil:
           typ = skipTypes(n[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink})
+          if expectedElementType == nil:
+            expectedElementType = typ
     if not isOrdinalType(typ, allowEnumWithHoles=true):
       localError(c.config, n.info, errOrdinalTypeExpected)
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
@@ -2477,7 +2521,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
         m = fitNode(c, typ, n[i], info)
       result.add m
 
-proc semTableConstr(c: PContext, n: PNode): PNode =
+proc semTableConstr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
   # we simply transform ``{key: value, key2, key3: value}`` to
   # ``[(key, value), (key2, value2), (key3, value2)]``
   result = newNodeI(nkBracket, n.info)
@@ -2499,7 +2543,7 @@ proc semTableConstr(c: PContext, n: PNode): PNode =
       lastKey = i+1
 
   if lastKey != n.len: illFormedAst(n, c.config)
-  result = semExpr(c, result)
+  result = semExpr(c, result, expectedType = expectedType)
 
 type
   TParKind = enum
@@ -2526,8 +2570,13 @@ proc checkPar(c: PContext; n: PNode): TParKind =
           localError(c.config, n[i].info, errNamedExprNotAllowed)
           return paNone
 
-proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = newNodeI(nkTupleConstr, n.info)
+  var expected: PType = nil
+  if expectedType != nil:
+    expected = expectedType.skipTypes(abstractRange-{tyDistinct})
+    if not (expected.kind == tyTuple and expected.len == n.len):
+      expected = nil
   var typ = newTypeS(tyTuple, c)
   typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
   var ids = initIntSet()
@@ -2537,7 +2586,9 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     let id = considerQuotedIdent(c, n[i][0])
     if containsOrIncl(ids, id.id):
       localError(c.config, n[i].info, errFieldInitTwice % id.s)
-    n[i][1] = semExprWithType(c, n[i][1], {})
+    # can check if field name matches expected type here
+    let expectedElemType = if expected != nil: expected[i] else: nil
+    n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType)
 
     if n[i][1].typ.kind == tyTypeDesc:
       localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@@ -2552,18 +2603,24 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result.add n[i]
   result.typ = typ
 
-proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
   result = n                  # we don't modify n, but compute the type:
   result.transitionSonsKind(nkTupleConstr)
+  var expected: PType = nil
+  if expectedType != nil:
+    expected = expectedType.skipTypes(abstractRange-{tyDistinct})
+    if not (expected.kind == tyTuple and expected.len == n.len):
+      expected = nil
   var typ = newTypeS(tyTuple, c)  # leave typ.n nil!
   for i in 0..<n.len:
-    n[i] = semExprWithType(c, n[i], {})
+    let expectedElemType = if expected != nil: expected[i] else: nil
+    n[i] = semExprWithType(c, n[i], {}, expectedElemType)
     addSonSkipIntLit(typ, n[i].typ, c.idgen)
   result.typ = typ
 
 include semobjconstr
 
-proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
+proc semBlock(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil): PNode =
   result = n
   inc(c.p.nestedBlockCounter)
   checkSonsLen(n, 2, c.config)
@@ -2578,7 +2635,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
     suggestSym(c.graph, n[0].info, labl, c.graph.usageSym)
     styleCheckDef(c, labl)
     onDef(n[0].info, labl)
-  n[1] = semExpr(c, n[1], flags)
+  n[1] = semExpr(c, n[1], flags, expectedType)
   n.typ = n[1].typ
   if isEmptyType(n.typ): n.transitionSonsKind(nkBlockStmt)
   else: n.transitionSonsKind(nkBlockExpr)
@@ -2644,8 +2701,8 @@ proc semExport(c: PContext, n: PNode): PNode =
 
         s = nextOverloadIter(o, c, a)
 
-proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
-  var tupexp = semTuplePositionsConstr(c, n, flags)
+proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
+  var tupexp = semTuplePositionsConstr(c, n, flags, expectedType)
   var isTupleType: bool
   if tupexp.len > 0: # don't interpret () as type
     isTupleType = tupexp[0].typ.kind == tyTypeDesc
@@ -2770,7 +2827,7 @@ proc semPragmaStmt(c: PContext; n: PNode) =
   else:
     pragma(c, c.p.owner, n, stmtPragmas, true)
 
-proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
   when defined(nimCompilerStacktraceHints):
     setFrameMsg c.config$n.info & " " & $n.kind
   when false: # see `tdebugutils`
@@ -2779,19 +2836,39 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     defer:
       if isCompilerDebug():
         echo ("<", c.config$n.info, n, ?.result.typ)
+  
+  template directLiteral(typeKind: TTypeKind) =
+    if result.typ == nil:
+      if expectedType != nil and (
+          let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+          expected.kind == typeKind):
+        result.typ = expected
+        changeType(c, result, expectedType, check=true)
+      else:
+        result.typ = getSysType(c.graph, n.info, typeKind)
 
   result = n
   if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
   if nfSem in n.flags: return
   case n.kind
   of nkIdent, nkAccQuoted:
-    let checks = if efNoEvaluateGeneric in flags:
-        {checkUndeclared, checkPureEnumFields}
-      elif efInCall in flags:
-        {checkUndeclared, checkModule, checkPureEnumFields}
-      else:
-        {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
-    var s = qualifiedLookUp(c, n, checks)
+    var s: PSym
+    if expectedType != nil and (
+        let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+        expected.kind == tyEnum):
+      let nameId = considerQuotedIdent(c, n).id
+      for f in expected.n:
+        if f.kind == nkSym and f.sym.name.id == nameId:
+          s = f.sym
+          break
+    if s == nil:
+      let checks = if efNoEvaluateGeneric in flags:
+          {checkUndeclared, checkPureEnumFields}
+        elif efInCall in flags:
+          {checkUndeclared, checkModule, checkPureEnumFields}
+        else:
+          {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
+      s = qualifiedLookUp(c, n, checks)
     if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
     case s.kind
     of skProc, skFunc, skMethod, skConverter, skIterator:
@@ -2811,6 +2888,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         result = semSym(c, n, s, flags)
     else:
       result = semSym(c, n, s, flags)
+    if expectedType != nil and isSymChoice(result):
+      result = fitNode(c, expectedType, result, n.info)
+      if result.kind == nkSym:
+        result = semSym(c, result, result.sym, flags)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
@@ -2818,39 +2899,56 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkEmpty, nkNone, nkCommentStmt, nkType:
     discard
   of nkNilLit:
-    if result.typ == nil: result.typ = getNilType(c)
+    if result.typ == nil:
+      result.typ = getNilType(c)
+      if expectedType != nil:
+        var m = newCandidate(c, result.typ)
+        if typeRel(m, expectedType, result.typ) >= isSubtype:
+          result.typ = expectedType
+        # or: result = fitNode(c, expectedType, result, n.info)
   of nkIntLit:
-    if result.typ == nil: setIntLitType(c, result)
-  of nkInt8Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8)
-  of nkInt16Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16)
-  of nkInt32Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32)
-  of nkInt64Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64)
-  of nkUIntLit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt)
-  of nkUInt8Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8)
-  of nkUInt16Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16)
-  of nkUInt32Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32)
-  of nkUInt64Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64)
-  #of nkFloatLit:
-  #  if result.typ == nil: result.typ = getFloatLitType(result)
-  of nkFloat32Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32)
-  of nkFloat64Lit, nkFloatLit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64)
-  of nkFloat128Lit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128)
+    if result.typ == nil:
+      if expectedType != nil and (
+          let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+          expected.kind in {tyInt..tyInt64,
+            tyUInt..tyUInt64,
+            tyFloat..tyFloat128}):
+        result.typ = expected
+        if expected.kind in {tyFloat..tyFloat128}:
+          n.transitionIntToFloatKind(nkFloatLit)
+        changeType(c, result, expectedType, check=true)
+      else:
+        setIntLitType(c, result)
+  of nkInt8Lit: directLiteral(tyInt8)
+  of nkInt16Lit: directLiteral(tyInt16)
+  of nkInt32Lit: directLiteral(tyInt32)
+  of nkInt64Lit: directLiteral(tyInt64)
+  of nkUIntLit: directLiteral(tyUInt)
+  of nkUInt8Lit: directLiteral(tyUInt8)
+  of nkUInt16Lit: directLiteral(tyUInt16)
+  of nkUInt32Lit: directLiteral(tyUInt32)
+  of nkUInt64Lit: directLiteral(tyUInt64)
+  of nkFloatLit:
+    if result.typ == nil:
+      if expectedType != nil and (
+          let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+          expected.kind in {tyFloat..tyFloat128}):
+        result.typ = expected
+        changeType(c, result, expectedType, check=true)
+      else:
+        result.typ = getSysType(c.graph, n.info, tyFloat64)
+  of nkFloat32Lit: directLiteral(tyFloat32)
+  of nkFloat64Lit: directLiteral(tyFloat64)
+  of nkFloat128Lit: directLiteral(tyFloat128)
   of nkStrLit..nkTripleStrLit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString)
-  of nkCharLit:
-    if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar)
+    if result.typ == nil:
+      if expectedType != nil and (
+          let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
+          expected.kind in {tyString, tyCstring}):
+        result.typ = expectedType
+      else:
+        result.typ = getSysType(c.graph, n.info, tyString)
+  of nkCharLit: directLiteral(tyChar)
   of nkDotExpr:
     result = semFieldAccess(c, n, flags)
     if result.kind == nkDotCall:
@@ -2858,7 +2956,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       result = semExpr(c, result, flags)
   of nkBind:
     message(c.config, n.info, warnDeprecated, "bind is deprecated")
-    result = semExpr(c, n[0], flags)
+    result = semExpr(c, n[0], flags, expectedType)
   of nkTypeOfExpr..nkTupleClassTy, nkStaticTy, nkRefTy..nkEnumTy:
     if c.matchedConcept != nil and n.len == 1:
       let modifier = n.modifierTypeKindOfNode
@@ -2884,40 +2982,40 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       #  pretty.checkUse(n[0][1].info, s)
       case s.kind
       of skMacro, skTemplate:
-        result = semDirectOp(c, n, flags)
+        result = semDirectOp(c, n, flags, expectedType)
       of skType:
         # XXX think about this more (``set`` procs)
         let ambig = c.isAmbiguous
         if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
-          result = semConv(c, n)
+          result = semConv(c, n, expectedType)
         elif ambig and n.len == 1:
           errorUseQualifier(c, n.info, s)
         elif n.len == 1:
-          result = semObjConstr(c, n, flags)
-        elif s.magic == mNone: result = semDirectOp(c, n, flags)
-        else: result = semMagic(c, n, s, flags)
+          result = semObjConstr(c, n, flags, expectedType)
+        elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType)
+        else: result = semMagic(c, n, s, flags, expectedType)
       of skProc, skFunc, skMethod, skConverter, skIterator:
         if s.magic == mNone: result = semDirectOp(c, n, flags)
-        else: result = semMagic(c, n, s, flags)
+        else: result = semMagic(c, n, s, flags, expectedType)
       else:
         #liMessage(n.info, warnUser, renderTree(n));
-        result = semIndirectOp(c, n, flags)
+        result = semIndirectOp(c, n, flags, expectedType)
     elif (n[0].kind == nkBracketExpr or shouldBeBracketExpr(n)) and
         isSymChoice(n[0][0]):
       # indirectOp can deal with explicit instantiations; the fixes
       # the 'newSeq[T](x)' bug
       setGenericParams(c, n[0])
-      result = semDirectOp(c, n, flags)
+      result = semDirectOp(c, n, flags, expectedType)
     elif nfDotField in n.flags:
-      result = semDirectOp(c, n, flags)
+      result = semDirectOp(c, n, flags, expectedType)
     elif isSymChoice(n[0]):
       let b = asBracketExpr(c, n)
       if b != nil:
-        result = semExpr(c, b, flags)
+        result = semExpr(c, b, flags, expectedType)
       else:
-        result = semDirectOp(c, n, flags)
+        result = semDirectOp(c, n, flags, expectedType)
     else:
-      result = semIndirectOp(c, n, flags)
+      result = semIndirectOp(c, n, flags, expectedType)
 
     if nfDefaultRefsParam in result.flags:
       result = result.copyTree #XXX: Figure out what causes default param nodes to be shared.. (sigmatch bug?)
@@ -2936,12 +3034,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         # This is a "when nimvm" stmt.
         result = semWhen(c, n, true)
       else:
-        result = semExpr(c, result, flags)
+        result = semExpr(c, result, flags, expectedType)
   of nkBracketExpr:
     checkMinSonsLen(n, 1, c.config)
-    result = semArrayAccess(c, n, flags)
+    result = semArrayAccess(c, n, flags, expectedType)
   of nkCurlyExpr:
-    result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags)
+    result = semExpr(c, buildOverloadedSubscripts(n, getIdent(c.cache, "{}")), flags, expectedType)
   of nkPragmaExpr:
     var
       pragma = n[1]
@@ -2963,12 +3061,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkPar, nkTupleConstr:
     case checkPar(c, n)
     of paNone: result = errorNode(c, n)
-    of paTuplePositions: result = semTupleConstr(c, n, flags)
-    of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
-    of paSingle: result = semExpr(c, n[0], flags)
-  of nkCurly: result = semSetConstr(c, n)
-  of nkBracket: result = semArrayConstr(c, n, flags)
-  of nkObjConstr: result = semObjConstr(c, n, flags)
+    of paTuplePositions: result = semTupleConstr(c, n, flags, expectedType)
+    of paTupleFields: result = semTupleFieldsConstr(c, n, flags, expectedType)
+    of paSingle: result = semExpr(c, n[0], flags, expectedType)
+  of nkCurly: result = semSetConstr(c, n, expectedType)
+  of nkBracket: result = semArrayConstr(c, n, flags, expectedType)
+  of nkObjConstr: result = semObjConstr(c, n, flags, expectedType)
   of nkLambdaKinds: result = semProcAux(c, n, skProc, lambdaPragmas, flags)
   of nkDerefExpr: result = semDeref(c, n)
   of nkAddr:
@@ -2978,9 +3076,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result.typ = makePtrType(c, result[0].typ)
   of nkHiddenAddr, nkHiddenDeref:
     checkSonsLen(n, 1, c.config)
-    n[0] = semExpr(c, n[0], flags)
+    n[0] = semExpr(c, n[0], flags, expectedType)
   of nkCast: result = semCast(c, n)
-  of nkIfExpr, nkIfStmt: result = semIf(c, n, flags)
+  of nkIfExpr, nkIfStmt: result = semIf(c, n, flags, expectedType)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
     checkSonsLen(n, 2, c.config)
     considerGenSyms(c, n)
@@ -2994,15 +3092,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     checkMinSonsLen(n, 2, c.config)
     considerGenSyms(c, n)
   of nkTableConstr:
-    result = semTableConstr(c, n)
+    result = semTableConstr(c, n, expectedType)
   of nkClosedSymChoice, nkOpenSymChoice:
     # handling of sym choices is context dependent
     # the node is left intact for now
     discard
-  of nkStaticExpr: result = semStaticExpr(c, n[0])
+  of nkStaticExpr: result = semStaticExpr(c, n[0], expectedType)
   of nkAsgn: result = semAsgn(c, n)
-  of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags)
-  of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
+  of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags, expectedType)
+  of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags, expectedType)
   of nkRaiseStmt: result = semRaise(c, n)
   of nkVarSection: result = semVarOrLet(c, n, skVar)
   of nkLetSection: result = semVarOrLet(c, n, skLet)
@@ -3010,10 +3108,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkTypeSection: result = semTypeSection(c, n)
   of nkDiscardStmt: result = semDiscard(c, n)
   of nkWhileStmt: result = semWhile(c, n, flags)
-  of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags)
+  of nkTryStmt, nkHiddenTryStmt: result = semTry(c, n, flags, expectedType)
   of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
   of nkForStmt, nkParForStmt: result = semFor(c, n, flags)
-  of nkCaseStmt: result = semCase(c, n, flags)
+  of nkCaseStmt: result = semCase(c, n, flags, expectedType)
   of nkReturnStmt: result = semReturn(c, n)
   of nkUsingStmt: result = semUsing(c, n)
   of nkAsmStmt: result = semAsm(c, n)
@@ -3052,7 +3150,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export")
     result = semExportExcept(c, n)
   of nkPragmaBlock:
-    result = semPragmaBlock(c, n)
+    result = semPragmaBlock(c, n, expectedType)
   of nkStaticStmt:
     result = semStaticStmt(c, n)
   of nkDefer: