diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a83da5849863..c90aa991bf78 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -617,7 +617,7 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = n[1] = makeTypeSymNode(c, lhsType, n[1].info) lhsType = n[1].typ else: - if c.inGenericContext > 0 and lhsType.base.containsGenericType: + if c.inGenericContext > 0 and lhsType.base.containsUnresolvedType: # BUGFIX: don't evaluate this too early: ``T is void`` return @@ -1504,7 +1504,16 @@ proc tryReadingGenericParam(c: PContext, n: PNode, i: PIdent, t: PType): PNode = result.typ = makeTypeFromExpr(c, copyTree(result)) else: result = nil - elif c.inGenericContext > 0 and t.containsGenericType: + of tyGenericBody, tyCompositeTypeClass: + if c.inGenericContext > 0: + result = readTypeParameter(c, t, i, n.info) + if result != nil: + # generic parameter exists, stop here but delay until instantiation + result = semGenericStmt(c, n) + result.typ = makeTypeFromExpr(c, copyTree(result)) + else: + result = nil + elif c.inGenericContext > 0 and t.containsUnresolvedType: result = semGenericStmt(c, n) result.typ = makeTypeFromExpr(c, copyTree(result)) else: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index b4fc319eca9e..759e8e6ab072 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -801,6 +801,14 @@ proc replaceTypesInBody*(p: PContext, pt: TypeMapping, n: PNode; result = replaceTypeVarsN(cl, n, expectedType = expectedType) popInfoContext(p.config) +proc prepareTypesInBody*(p: PContext, pt: TypeMapping, n: PNode; + owner: PSym = nil): PNode = + var typeMap = initLayeredTypeMap(pt) + var cl = initTypeVars(p, typeMap, n.info, owner) + pushInfoContext(p.config, n.info) + result = prepareNode(cl, n) + popInfoContext(p.config) + when false: # deadcode proc replaceTypesForLambda*(p: PContext, pt: TIdTable, n: PNode; diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e1f197679852..17d2e7a4dbd6 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -139,7 +139,7 @@ proc matchGenericParam(m: var TCandidate, formal: PType, n: PNode) = # don't match yet-unresolved generic instantiations while arg != nil and arg.kind == tyGenericParam: arg = idTableGet(m.bindings, arg) - if arg == nil or arg.containsGenericType: + if arg == nil or arg.containsUnresolvedType: m.state = csNoMatch return # fix up the type to get ready to match formal: @@ -2048,7 +2048,7 @@ 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 c.c.inGenericContext > 0 and a.containsGenericType: + if c.c.inGenericContext > 0 and a.containsUnresolvedType: # generic type bodies can sometimes compile call expressions # prevent unresolved generic parameters from being passed to procs as # typedesc parameters @@ -2087,7 +2087,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # also prevent infinite recursion below return isNone inc c.c.inGenericContext # to generate tyFromExpr again if unresolved - let reevaluated = tryResolvingStaticExpr(c, f.n, allowCalls = true).typ + # use prepareNode for consistency with other tyFromExpr in semtypinst: + let instantiated = prepareTypesInBody(c.c, c.bindings, f.n) + let reevaluated = c.c.semExpr(c.c, instantiated).typ dec c.c.inGenericContext case reevaluated.kind of tyFromExpr: diff --git a/compiler/types.nim b/compiler/types.nim index 2333672d27ee..60d81206886f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1494,6 +1494,23 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool = proc containsGenericType*(t: PType): bool = result = iterOverType(t, containsGenericTypeIter, nil) +proc containsUnresolvedTypeIter(t: PType, closure: RootRef): bool = + if tfUnresolved in t.flags: return true + case t.kind + of tyStatic: + return t.n == nil + of tyTypeDesc: + if t.base.kind == tyNone: return true + if containsUnresolvedTypeIter(t.base, closure): return true + return false + of tyGenericInvocation, tyGenericParam, tyFromExpr, tyAnything: + return true + else: + return false + +proc containsUnresolvedType*(t: PType): bool = + result = iterOverType(t, containsUnresolvedTypeIter, nil) + proc baseOfDistinct*(t: PType; g: ModuleGraph; idgen: IdGenerator): PType = if t.kind == tyDistinct: result = t.elementType diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index a1f5a0cb6193..308b1f33e0b8 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -435,3 +435,9 @@ block: # issue #24090 proc foo[T: M](x: T = default(T)) = discard x foo[M[int]]() doAssert not compiles(foo()) + +block: # above but encountered by sigmatch using replaceTypeVarsN + type Opt[T] = object + proc none[T](x: type Opt, y: typedesc[T]): Opt[T] = discard + proc foo[T](x: T, a = Opt.none(int)) = discard + foo(1, a = Opt.none(int))