From 2f904535d06472481c172b140c363d3cd717e02e Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 10 Oct 2024 16:35:51 +0300 Subject: [PATCH] don't allow instantiations resolving to generic body types (#24273) fixes #24091, refs #24092 Any instantiations resolving to a generic body type now gives an error. Due to #24092, this does not error in cases like matching against `type M` in generics because generic body type symbols are just not instantiated. But this prevents parameters with type `type M` from being used, although there doesn't seem to be any code which does this. Just in case such code exists, we still allow `typedesc` types resolving to generic body types. --- compiler/seminst.nim | 4 +++- tests/generics/tgenericbodyreturn1.nim | 9 +++++++++ tests/generics/tgenericbodyreturn2.nim | 11 +++++++++++ tests/generics/tgenericbodyreturn3.nim | 13 +++++++++++++ tests/generics/tuninstantiatedgenericcalls.nim | 14 +++++++------- 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 tests/generics/tgenericbodyreturn1.nim create mode 100644 tests/generics/tgenericbodyreturn2.nim create mode 100644 tests/generics/tgenericbodyreturn3.nim diff --git a/compiler/seminst.nim b/compiler/seminst.nim index d5afb8389f..b9b1a97be1 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -53,7 +53,9 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable): if q.typ.kind != tyCompositeTypeClass: localError(c.config, a.info, errCannotInstantiateX % s.name.s) t = errorType(c) - elif t.kind in {tyGenericParam, tyConcept, tyFromExpr}: + elif t.kind in {tyGenericParam, tyConcept, tyFromExpr} or + # generic body types are accepted as typedesc arguments + (t.kind == tyGenericBody and q.typ.kind != tyTypeDesc): localError(c.config, a.info, errCannotInstantiateX % q.name.s) t = errorType(c) elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or diff --git a/tests/generics/tgenericbodyreturn1.nim b/tests/generics/tgenericbodyreturn1.nim new file mode 100644 index 0000000000..110498f4d9 --- /dev/null +++ b/tests/generics/tgenericbodyreturn1.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "cannot instantiate: 'T'" + file: "system.nim" +""" + +# issue #24091 + +type M[V] = object +echo default(M) diff --git a/tests/generics/tgenericbodyreturn2.nim b/tests/generics/tgenericbodyreturn2.nim new file mode 100644 index 0000000000..8327d6b968 --- /dev/null +++ b/tests/generics/tgenericbodyreturn2.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "cannot instantiate: 'T'" + file: "system.nim" +""" + +# issue #24091 + +type M[V] = object +type Foo = object # notice not generic + x: typeof(default(M)) +echo Foo() # () diff --git a/tests/generics/tgenericbodyreturn3.nim b/tests/generics/tgenericbodyreturn3.nim new file mode 100644 index 0000000000..7fb0767966 --- /dev/null +++ b/tests/generics/tgenericbodyreturn3.nim @@ -0,0 +1,13 @@ +discard """ + errormsg: "cannot instantiate: 'ShouldNotResolve'" +""" + +# issue #24091 + +type Generic[U] = object +proc foo[ShouldNotResolve](x: typedesc[ShouldNotResolve]): ShouldNotResolve = + echo ShouldNotResolve # Generic + echo declared(result) # true + echo typeof(result) # Generic +echo typeof(foo(Generic)) # void +foo(Generic) diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index f33fc8967c..b21c1f981d 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -421,17 +421,17 @@ block: # issue #24090 doAssert a.x is M[int] var b: Foo[float] doAssert b.x is M[float] + # related to #24091: doAssert not (compiles do: type Bar[T] = object - x: typeof(M()) # actually fails here immediately - var bar: Bar[int]) + # ideally fails here immediately since the inside of `typeof` does not + # depend on an unresolved parameter + # but if typechecking gets too lazy, then we need to instantiate to error + x: typeof(M())) doAssert not (compiles do: type Bar[T] = object - x: typeof(default(M)) - var bar: Bar[int] - # gives "undeclared identifier x" because of #24091, - # normally it should fail in the line above - echo bar.x) + # again, ideally fails here immediately + x: typeof(default(M))) proc foo[T: M](x: T = default(T)) = discard x foo[M[int]]() doAssert not compiles(foo())