diff options
author | metagn <metagngn@gmail.com> | 2023-06-13 21:05:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-13 20:05:44 +0200 |
commit | 894a19c6ed20ecfc72ea4bda010c11371b571d45 (patch) | |
tree | 42677f9bccf28d504723550bbc3b4cc12946f90f /compiler | |
parent | 606e9941d0c42a361b519038dfff3af061eba381 (diff) | |
download | Nim-894a19c6ed20ecfc72ea4bda010c11371b571d45.tar.gz |
fix calls in generic bodies, delay typecheck when no overloads match (#22029)
* sacrifice "tgenericshardcases" for working statics * legacy switch for CI, maybe experimental later * convert to experimental * apparently untyped needs the experimental switch * try special case call semcheck * try fix * fix compilation * final cleanup, not experimental, make `when` work * remove last needed use of untyped * fix unused warning in test * remove untyped feature
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/semcall.nim | 5 | ||||
-rw-r--r-- | compiler/semexprs.nim | 5 | ||||
-rw-r--r-- | compiler/seminst.nim | 3 | ||||
-rw-r--r-- | compiler/semtypes.nim | 19 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 46 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 8 | ||||
-rw-r--r-- | compiler/types.nim | 5 |
7 files changed, 59 insertions, 32 deletions
diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 8445b25e7..c0317f4d6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -627,7 +627,10 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, candidates) result = semResolvedCall(c, r, n, flags) else: - if efExplain notin flags: + if efDetermineType in flags and c.inGenericContext > 0 and c.matchedConcept == nil: + result = n + result.typ = makeTypeFromExpr(c, result.copyTree) + elif efExplain notin flags: # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 53c0790fe..3b40425cf 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -971,7 +971,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, if result != nil: if result[0].kind != nkSym: - internalError(c.config, "semOverloadedCallAnalyseEffects") + if not (efDetermineType in flags and c.inGenericContext > 0): + internalError(c.config, "semOverloadedCallAnalyseEffects") return let callee = result[0].sym case callee.kind @@ -1007,6 +1008,8 @@ proc setGenericParams(c: PContext, n: 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) + if n.typ != nil and n.typ.kind == tyFromExpr and c.inGenericContext > 0: + return n result = n diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 3afbedec7..b4b5ad0a2 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -388,8 +388,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, pragma(c, result, n[pragmasPos], allRoutinePragmas) if isNil(n[bodyPos]): n[bodyPos] = copyTree(getBody(c.graph, fn)) - if c.inGenericContext == 0: - instantiateBody(c, n, fn.typ.n, result, fn) + instantiateBody(c, n, fn.typ.n, result, fn) sideEffectsCheck(c, result) if result.magic notin {mSlice, mTypeOf}: # 'toOpenArray' is special and it is allowed to return 'openArray': diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 14ad72fca..a9fc980db 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -269,6 +269,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, "range is empty") var range: array[2, PNode] + # XXX this is still a hard compilation in a generic context, this can + # result in unresolved generic parameters being treated like real types range[0] = semExprWithType(c, n[1], {efDetermineType}) range[1] = semExprWithType(c, n[2], {efDetermineType}) @@ -277,7 +279,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit(c.idgen) let hasUnknownTypes = c.inGenericContext > 0 and - rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr + (rangeT[0].kind == tyFromExpr or rangeT[1].kind == tyFromExpr) if not hasUnknownTypes: if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})): @@ -337,6 +339,8 @@ proc semArrayIndex(c: PContext, n: PNode): PType = elif n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "..<": result = errorType(c) else: + # XXX this is still a hard compilation in a generic context, this can + # result in unresolved generic parameters being treated like real types let e = semExprWithType(c, n, {efDetermineType}) if e.typ.kind == tyFromExpr: result = makeRangeWithStaticExpr(c, e.typ.n) @@ -357,7 +361,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) # This is an int returning call, depending on an - # yet unknown generic param (see tgenericshardcases). + # yet unknown generic param (see tuninstantiatedgenericcalls). # We are going to construct a range type that will be # properly filled-out in semtypinst (see how tyStaticExpr # is handled there). @@ -380,7 +384,8 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = let indx = semArrayIndex(c, n[1]) var indxB = indx if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = lastSon(indxB) - if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr}: + if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and + tfUnresolved notin indxB.flags: if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}: discard elif not isOrdinalType(indxB): @@ -737,7 +742,13 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, if e.kind != nkIntLit: discard "don't report followup error" elif e.intVal != 0 and branch == nil: branch = it[1] else: - it[0] = forceBool(c, semExprWithType(c, it[0])) + # XXX this is still a hard compilation in a generic context, this can + # result in unresolved generic parameters being treated like real types + let e = semExprWithType(c, it[0], {efDetermineType}) + if e.typ.kind == tyFromExpr: + it[0] = makeStaticExpr(c, e) + else: + it[0] = forceBool(c, e) of nkElse: checkSonsLen(it, 1, c.config) if branch == nil: branch = it[0] diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 50dba515d..7c9bf9039 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -141,27 +141,28 @@ proc isTypeParam(n: PNode): bool = (n.sym.kind == skGenericParam or (n.sym.kind == skType and sfFromGeneric in n.sym.flags)) -proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode = - # This is needed for tgenericshardcases - # It's possible that a generic param will be used in a proc call to a - # typedesc accepting proc. After generic param substitution, such procs - # should be optionally instantiated with the correct type. In order to - # perform this instantiation, we need to re-run the generateInstance path - # in the compiler, but it's quite complicated to do so at the moment so we - # resort to a mild hack; the head symbol of the call is temporary reset and - # overload resolution is executed again (which may trigger generateInstance). - if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags: - var needsFixing = false - for i in 1..<n.safeLen: - if isTypeParam(n[i]): needsFixing = true - if needsFixing: - n[0] = newSymNode(n[0].sym.owner) - return cl.c.semOverloadedCall(cl.c, n, n, {skProc, skFunc}, {}) - - for i in 0..<n.safeLen: - n[i] = reResolveCallsWithTypedescParams(cl, n[i]) - - return n +when false: # old workaround + proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode = + # This is needed for tuninstantiatedgenericcalls + # It's possible that a generic param will be used in a proc call to a + # typedesc accepting proc. After generic param substitution, such procs + # should be optionally instantiated with the correct type. In order to + # perform this instantiation, we need to re-run the generateInstance path + # in the compiler, but it's quite complicated to do so at the moment so we + # resort to a mild hack; the head symbol of the call is temporary reset and + # overload resolution is executed again (which may trigger generateInstance). + if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags: + var needsFixing = false + for i in 1..<n.safeLen: + if isTypeParam(n[i]): needsFixing = true + if needsFixing: + n[0] = newSymNode(n[0].sym.owner) + return cl.c.semOverloadedCall(cl.c, n, n, {skProc, skFunc}, {}) + + for i in 0..<n.safeLen: + n[i] = reResolveCallsWithTypedescParams(cl, n[i]) + + return n proc replaceObjBranches(cl: TReplTypeVars, n: PNode): PNode = result = n @@ -250,7 +251,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode = result = newNodeI(nkRecList, n.info) of nkStaticExpr: var n = prepareNode(cl, n) - n = reResolveCallsWithTypedescParams(cl, n) + when false: + n = reResolveCallsWithTypedescParams(cl, n) result = if cl.allowMetaTypes: n else: cl.c.semExpr(cl.c, n) if not cl.allowMetaTypes: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c3d524791..d6740a7e8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1837,7 +1837,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # proc foo(T: typedesc, x: T) # when `f` is an unresolved typedesc, `a` could be any # type, so we should not perform this check earlier - if a.kind != tyTypeDesc: + if c.c.inGenericContext > 0 and + a.skipTypes({tyTypeDesc}).kind == tyGenericParam: + # generic type bodies can sometimes compile call expressions + # prevent unresolved generic parameters from being passed to procs as + # typedesc parameters + result = isNone + elif a.kind != tyTypeDesc: if a.kind == tyGenericParam and tfWildcard in a.flags: # TODO: prevent `a` from matching as a wildcard again result = isGeneric diff --git a/compiler/types.nim b/compiler/types.nim index 353c445a6..4a7514370 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -209,6 +209,8 @@ proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, # a leaf result = iterOverTypeAux(marker, n.typ, iter, closure) else: + result = iterOverTypeAux(marker, n.typ, iter, closure) + if result: return for i in 0..<n.len: result = iterOverNode(marker, n[i], iter, closure) if result: return @@ -480,6 +482,7 @@ proc valueToString(a: PNode): string = result = $a.intVal of nkFloatLit..nkFloat128Lit: result = $a.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal + of nkStaticExpr: result = "static(" & a[0].renderTree & ")" else: result = "<invalid value>" proc rangeToStr(n: PNode): string = @@ -1513,7 +1516,7 @@ proc compatibleEffects*(formal, actual: PType): EffectsCompat = proc isCompileTimeOnly*(t: PType): bool {.inline.} = - result = t.kind in {tyTypeDesc, tyStatic} + result = t.kind in {tyTypeDesc, tyStatic, tyGenericParam} proc containsCompileTimeOnly*(t: PType): bool = if isCompileTimeOnly(t): return true |