Skip to content

Commit

Permalink
top-down type inference, implements rfc 149 (#20091)
Browse files Browse the repository at this point in the history
* micro implementation of rfc 149

refs nim-lang/RFCs#149

* number/array/seq literals, more statements

* try fix number literal alias issue

* renew expectedType with if/case/try branch types

* fix (nerf) index type handling and float typed int

* use typeAllowed

* tweaks + const test (tested locally) [skip ci]

* fill out more of the checklist

* more literals, change @ order, type conversions

Not copying the full call tree before the typedesc call check
in `semIndirectOp` is also a small performance improvement.

* disable self-conversion warning

* revert type conversions (maybe separate op later)

* deal with CI for now (seems unrelated), try enums

* workaround CI different way

* proper fix

* again

* see sizes

* lol

* overload selection, simplify int literal -> float

* range, new @ solution, try use fitNode for nil

* use new magic

* try fix ranges, new magic, deal with #20193

* add documentation, support templates

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
  • Loading branch information
metagn and Araq authored Aug 24, 2022
1 parent 2dcfd73 commit 0014b9c
Show file tree
Hide file tree
Showing 17 changed files with 599 additions and 199 deletions.
11 changes: 9 additions & 2 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ type
mInSet, mRepr, mExit,
mSetLengthStr, mSetLengthSeq,
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
Expand Down Expand Up @@ -708,8 +708,8 @@ type
mSymIsInstantiationOf, mNodeId, mPrivateAccess


# things that we can evaluate safely at compile time, even if not asked for it:
const
# things that we can evaluate safely at compile time, even if not asked for it:
ctfeWhitelist* = {mNone, mSucc,
mPred, mInc, mDec, mOrd, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq,
Expand Down Expand Up @@ -738,6 +738,9 @@ const
mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet,
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInSet, mRepr}

generatedMagics* = {mNone, mIsolate, mFinished, mOpenArrayToSeq}
## magics that are generated as normal procs in the backend

type
ItemId* = object
Expand Down Expand Up @@ -1677,6 +1680,10 @@ proc transitionIntKind*(n: PNode, kind: range[nkCharLit..nkUInt64Lit]) =
transitionNodeKindCommon(kind)
n.intVal = obj.intVal

proc transitionIntToFloatKind*(n: PNode, kind: range[nkFloatLit..nkFloat128Lit]) =
transitionNodeKindCommon(kind)
n.floatVal = BiggestFloat(obj.intVal)

proc transitionNoneToSym*(n: PNode) =
transitionNodeKindCommon(nkSym)

Expand Down
5 changes: 3 additions & 2 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2369,7 +2369,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate, mFinished: genCall(p, e, d)
of generatedMagics: genCall(p, e, d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
Expand Down Expand Up @@ -2978,7 +2978,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if n[genericParamsPos].kind == nkEmpty:
var prc = n[namePos].sym
if useAliveDataFromDce in p.module.flags:
if p.module.alive.contains(prc.itemId.item) and prc.magic in {mNone, mIsolate, mFinished}:
if p.module.alive.contains(prc.itemId.item) and
prc.magic in generatedMagics:
genProc(p.module, prc)
elif prc.skipGenericOwner.kind == skModule and sfCompileTime notin prc.flags:
if ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasEffectsOf")

defineSymbol("nimHasEnforceNoRaises")
defineSymbol("nimHasTopDownInference")
defineSymbol("nimHasTemplateRedefinitionPragma")
6 changes: 4 additions & 2 deletions compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1455,7 +1455,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
s.name.s)
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics or
{sfImportc, sfInfixCall} * s.flags != {}:
discard
elif s.kind == skMethod and getBody(p.module.graph, s).kind == nkEmpty:
Expand Down Expand Up @@ -2106,6 +2106,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[1], x)
useMagic(p, "nimCopy")
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
of mOpenArrayToSeq:
genCall(p, n, r)
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
Expand Down Expand Up @@ -2622,7 +2624,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
let s = n[namePos].sym
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
if lfNoDecl in s.loc.flags or s.magic notin generatedMagics: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
p.locals.add(genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)
Expand Down
44 changes: 22 additions & 22 deletions compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ when not defined(leanCompiler):

# implementation

proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode
proc semExprNoType(c: PContext, n: PNode): PNode
proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc semProcBody(c: PContext, n: PNode; expectedType: PType = nil): PNode

proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
Expand All @@ -48,7 +48,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode
proc finishMethod(c: PContext, s: PSym)
proc evalAtCompileTime(c: PContext, n: PNode): PNode
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode): PNode
proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode
proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType
proc semTypeOf(c: PContext; n: PNode): PNode
proc computeRequiresInit(c: PContext, t: PType): bool
Expand Down Expand Up @@ -269,12 +269,12 @@ proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(c, typ.n.info, typ, skProc)

proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode
flags: TExprFlags = {}; expectedType: PType = nil): PNode

proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym =
if t.sym != nil: return t.sym
Expand Down Expand Up @@ -334,8 +334,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
isArrayConstr(arg):
arg.typ = eOrig.typ

proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil: return

result = getConstExpr(c.module, e, c.idgen, c.graph)
Expand Down Expand Up @@ -365,8 +365,8 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
const
errConstExprExpected = "constant expression expected"

proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
proc semConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
var e = semExprWithType(c, n, expectedType = expectedType)
if e == nil:
localError(c.config, n.info, errConstExprExpected)
return n
Expand All @@ -388,14 +388,14 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
else:
result = fixupTypeAfterEval(c, result, e)

proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNeedStatic in flags:
if efPreferNilResult in flags:
return tryConstExpr(c, n)
return tryConstExpr(c, n, expectedType)
else:
return semConstExpr(c, n)
return semConstExpr(c, n, expectedType)
else:
result = semExprWithType(c, n, flags)
result = semExprWithType(c, n, flags, expectedType)
if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result, c.idgen, c.graph)
if evaluated != nil: return evaluated
Expand All @@ -414,7 +414,7 @@ proc resetSemFlag(n: PNode) =
resetSemFlag(n[i])

proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
s: PSym, flags: TExprFlags): PNode =
s: PSym, flags: TExprFlags; expectedType: PType = nil): PNode =
## Semantically check the output of a macro.
## This involves processes such as re-checking the macro output for type
## coherence, making sure that variables declared with 'let' aren't
Expand All @@ -438,10 +438,10 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
case retType.kind
of tyUntyped:
# Not expecting a type here allows templates like in ``tmodulealias.in``.
result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
of tyTyped:
# More restrictive version.
result = semExprWithType(c, result, flags)
result = semExprWithType(c, result, flags, expectedType)
of tyTypeDesc:
if result.kind == nkStmtList: result.transitionSonsKind(nkStmtListType)
var typ = semTypeNode(c, result, nil)
Expand All @@ -465,7 +465,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)

result = semExpr(c, result, flags)
result = semExpr(c, result, flags, expectedType)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
dec(c.config.evalTemplateCounter)
Expand All @@ -476,7 +476,7 @@ const
errFloatToString = "cannot convert '$1' to '$2'"

proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
flags: TExprFlags = {}; expectedType: PType = nil): PNode =
rememberExpansion(c, nOrig.info, sym)
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)

Expand All @@ -496,7 +496,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.idgen, c.graph, c.templInstCounter, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
result = semAfterMacroCall(c, n, result, sym, flags, expectedType)
if c.config.macrosToExpand.hasKey(sym.name.s):
message(c.config, nOrig.info, hintExpandMacro, renderTree(result))
result = wrapInComesFrom(nOrig.info, sym, result)
Expand All @@ -507,7 +507,7 @@ proc forceBool(c: PContext, n: PNode): PNode =
if result == nil: result = n

proc semConstBoolExpr(c: PContext, n: PNode): PNode =
result = forceBool(c, semConstExpr(c, n))
result = forceBool(c, semConstExpr(c, n, getSysType(c.graph, n.info, tyBool)))
if result.kind != nkIntLit:
localError(c.config, n.info, errConstExprExpected)

Expand Down
6 changes: 3 additions & 3 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ type
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
# to some new symbol in a generic instantiation
libs*: seq[PLib] # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode {.nimcall.}
semTryExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
semTryConstExpr*: proc (c: PContext, n: PNode; expectedType: PType = nil): PNode {.nimcall.}
computeRequiresInit*: proc (c: PContext, t: PType): bool {.nimcall.}
hasUnresolvedArgs*: proc (c: PContext, n: PNode): bool

Expand Down
Loading

0 comments on commit 0014b9c

Please sign in to comment.