E06021: a generic function infers its type arguments only when its parameters are exactly its type parameters, in order; parameterise it explicitly

Category: E06xxx Type hierarchy checks · Reported in phase: FULL_RESOLUTION · Classification: GENERIC_FUNCTION_TYPE_ARGUMENTS_NOT_INFERRED · All error codes

What went wrong

A call to a generic function tried to infer its type arguments from its arguments, but the function is not in the one shape that can be inferred. A generic function infers its type arguments ONLY when its parameters are exactly its type parameters, in order, and nothing else - then argument 1's type is type argument 1, and so on. Any other shape - a parameter of 'List of T', a 'T' beside an 'Integer', 'T' twice, no 'T' at all, or the type parameters in a different order - says nothing reliable about what 'T' is, so EK9 does not guess.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 681 (What is the correct syntax for generic type parameterization...)
  • ek9 -q 58 (How do generic functions work in EK9?)

How to fix it

  1. Parameterise the function explicitly and call the result:
counter <- countOf() of String
stdout.println($counter(names))
  1. Or, where the function is yours, give it the inferring shape: its parameters exactly its type parameters, in order ('-> item as T').

Infers

identity() of type T  -> item as T                 identity(42)
pair() of type (K, V) -> key as K, amount as V     pair("a", 1)

[DOES NOT INFER - write 'f() of X']

countOf() of type T   -> items as List of T
tag() of type T       -> item as T, count as Integer
findMax() of type T   -> first as T, second as T
repeat() of type T    -> count as Integer
pick() of type (A, B) -> second as B, first as A

Rationale

This is the same rule as a generic class's inferring constructor (E06050): one shape, where the arguments ARE the type arguments. There is no unification - reading an argument's type as a type argument in any other shape type-checks the wrong thing.

Common causes

  • Expecting 'T' to be worked out from 'List of T' (as Java or Kotlin do)
  • A generic function with an extra non-generic parameter
  • Calling a function that takes two values of one 'T'

See also

  • E06021: type arguments cannot be inferred from this call (this error)
  • E06050: a generic class's inferring constructor shape
  • E06010: a generic used with no type arguments at all
  • E06270: arguments that do not match the (parameterised) function

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E06021: a generic function infers its type arguments only when its parameters are exactly its type parameters, in order; parameterise it explicitly

#!ek9
defines module error.e06021.bad

  defines function

    countOf() of type T
      -> items as List of T
      <- rtn as Integer: length items

    tag() of type T
      ->
        item as T
        count as Integer
      <- rtn as String: `${item}:${count}`

  defines program

    Inference()
      names <- ["a", "b"]

      //'T' sits inside 'List of T': the parameters are not exactly the type parameters
      howMany <- countOf(names)

      //A 'T' and an 'Integer': two arguments, one type parameter
      tagged <- tag("x", 3)

Fixed: Parameterise the generic function explicitly - 'countOf() of String' - and call the result

#!ek9
defines module error.e06021.good

  defines function

    countOf() of type T
      -> items as List of T
      <- rtn as Integer: length items

    tag() of type T
      ->
        item as T
        count as Integer
      <- rtn as String: `${item}:${count}`

  defines program

    Inference()
      stdout <- Stdout()
      names <- ["a", "b"]

      counter <- countOf() of String
      stdout.println($counter(names))

      tagger <- tag() of String
      stdout.println(tagger("x", 3))