diff --git a/compiler/ast/report_enums.nim b/compiler/ast/report_enums.nim index b2f17deb930..80471922f3a 100644 --- a/compiler/ast/report_enums.nim +++ b/compiler/ast/report_enums.nim @@ -360,6 +360,7 @@ type rsemCannotInstantiate rsemCannotInstantiateWithParameter + rsemCannotInstantiateForwarded rsemCannotGenerateGenericDestructor rsemUndeclaredField rsemExpectedOrdinal diff --git a/compiler/front/cli_reporter.nim b/compiler/front/cli_reporter.nim index f06d5b9cff4..e9e9616839e 100644 --- a/compiler/front/cli_reporter.nim +++ b/compiler/front/cli_reporter.nim @@ -790,6 +790,10 @@ proc reportBody*(conf: ConfigRef, r: SemReport): string = r.ownerSym.name.s ) + of rsemCannotInstantiateForwarded: + result = "cannot instantiate generic procedure forward-declared in " & + "another module" + of rsemTypeKindMismatch: result = r.str result.add " got '$1'" % typeToString(r.actualType) diff --git a/compiler/sem/seminst.nim b/compiler/sem/seminst.nim index a47e0fea606..985785ecade 100644 --- a/compiler/sem/seminst.nim +++ b/compiler/sem/seminst.nim @@ -401,6 +401,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, n[genericParamsPos] = c.graph.emptyNode var oldPrc = genericCacheGet(c.graph, fn, entry[], c.compilesContextId) if oldPrc == nil: + if sfForward in fn.flags and fn.itemId.module != c.module.itemId.module: + localReport(c.config, info, reportSem(rsemCannotInstantiateForwarded)) + # don't abort instantiation; let it complete for the sake of error + # correction (check/suggest) + # we MUST not add potentially wrong instantiations to the caching mechanism. # This means recursive instantiations behave differently when in # a ``compiles`` context but this is the lesser evil. See diff --git a/tests/lang_callable/generics/mgeneric_cycle_forward.nim b/tests/lang_callable/generics/mgeneric_cycle_forward.nim new file mode 100644 index 00000000000..22bef725b8e --- /dev/null +++ b/tests/lang_callable/generics/mgeneric_cycle_forward.nim @@ -0,0 +1,5 @@ +import tgeneric_cycle_forward + +forwarded[int]() # was already instantiated; works +# try to instantiate the incomplete generic routine: +forwarded[float]() diff --git a/tests/lang_callable/generics/tgeneric_cycle_forward.nim b/tests/lang_callable/generics/tgeneric_cycle_forward.nim new file mode 100644 index 00000000000..7f72e20fb18 --- /dev/null +++ b/tests/lang_callable/generics/tgeneric_cycle_forward.nim @@ -0,0 +1,20 @@ +discard """ + description: ''' + Ensure instantiating foreign, incomplete generic procedures leads to a + proper error. + ''' + errormsg: "cannot instantiate generic procedure forward-declared in another module" + file: "mgeneric_cycle_forward.nim" + line: 5 +""" + +proc forwarded*[T]() + +# instantiate with `int` before starting the import cycle +forwarded[int]() + +import mgeneric_cycle_forward # start the recursive import + +# complete the forward declaration: +proc forwarded[T]() = + discard