summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semexprs.nim13
-rw-r--r--compiler/semtypinst.nim8
-rw-r--r--compiler/sigmatch.nim8
-rw-r--r--compiler/types.nim17
-rw-r--r--tests/generics/tuninstantiatedgenericcalls.nim6
5 files changed, 47 insertions, 5 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a83da5849..c90aa991b 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 b4fc319ec..759e8e6ab 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 e1f197679..17d2e7a4d 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 2333672d2..60d812068 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 a1f5a0cb6..308b1f33e 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))