E10032: a constructor the generic uses on T from a pure scope ('T()', or the copy constructor 'T(T)' a for-range uses) must be pure on the type used to parameterise it

Category: E10xxx IR generation · Reported in phase: POST_RESOLUTION_CHECKS · Classification: CONSTRUCTOR_NOT_PURE_FOR_PARAMETERISATION · All error codes

What went wrong

The generic type uses a constructor of T from a PURE context, but the type used to parameterise it has no PURE constructor to serve it. Two uses do this:

  • 'T()' called inside a pure method, constructor or function of the generic
  • a for-range over T ('for item in first ... last') inside a pure scope - the range builds its counter as T(first) and each loop variable as T(counter), so it calls T's copy constructor T(T)

A pure generic can only call pure operations, and that requirement passes through to the type it is parameterised with.

How to fix it

  1. Mark the constructor of your type that the generic uses as pure - its no-argument constructor for 'T()', its copy constructor for a range (the [EXAMPLE] section below: a PureNoArgThing whose no-argument constructor is 'as pure', parameterising a pure PureHolder)
  2. Or parameterise with a type whose constructor is already pure.
  3. Or, if the generic does not need to be pure, drop 'as pure' from the generic operation that calls 'T()' or ranges over T.

Rationale

Purity in EK9 is checked, not advisory. A pure generic promises it mutates nothing; constructing T is part of what it does, so T's constructor has to keep that promise too, or the guarantee would be false after monomorphisation. A for-range is no exception: its copy constructor is a call like any other (on a concrete range type the same rule is E08130).

Common causes

  • The type has a public no-argument constructor that is not marked pure
  • The type's copy constructor is not pure and a pure generic ranges over T
  • Parameterising a pure generic with a type designed for a non-pure context

See also

  • E10031: 'T()' needs a public no-argument constructor
  • E08272: a range over a type needs a public copy constructor T(T)
  • E08130: a non-pure call in a pure scope
  • E06090: constructors must be pure for parameterisation

Examples

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

Fails with E10032: a constructor the generic uses on T from a pure scope ('T()', or the copy constructor 'T(T)' a for-range uses) must be pure on the type used to parameterise it

#!ek9
defines module error.e10032.bad

  defines class

    PureHolder of type T
      item as T?

      PureHolder() as pure
        item :=? T()

      PureHolder() as pure
        -> initial as T
        item :=? initial

      default operator ?

    NonPureNoArgThing
      content as String?

      NonPureNoArgThing()
        content :=? "default"

      default operator ?

  defines function

    tryNonPureNoArg()
      held <- PureHolder() of NonPureNoArgThing
      require held?

Fixed: Mark the no-argument constructor pure

#!ek9
defines module error.e10032.good

  defines class

    PureHolder of type T
      item as T?

      PureHolder() as pure
        item :=? T()

      PureHolder() as pure
        -> initial as T
        item :=? initial

      default operator ?

    PureNoArgThing
      content as String?

      PureNoArgThing() as pure
        content :=? "default"

      default operator ?

  defines function

    tryPureNoArg()
      held <- PureHolder() of PureNoArgThing
      require held?