E4053

E4053#

Invalid type for “self”: must be a type constructor.

This error happens when you want to define a method for implement a trait for a type that is not a type constructor.

Types that are type constructors:

  • Tuple: (Int, Bool)

  • enums, structs, traits, new types (type), and error types (type!).

Types that are not type constructors:

  • Function: (Int) -> Bool

  • Type parameter: T in fn f[T](x : T) -> T

错误示例#

  • Defining a method for a type that is not type constructor.

    fn f[T](self : T) -> Int { // Error: Invalid type for "self": must be a type constructor.
      ignore(self)
      0
    }
    
    fn g(self : (Int) -> Unit) -> Unit { // Error: Invalid type for "self": must be a type constructor.
      self(0)
    }
    
  • Implementing a method for a type that is not a type constructor.

    pub trait A {
      f(Self) -> Int
    }
    
    // Without constraints
    impl[X] A for X with f(self : X) -> Int { // Error: Invalid type for "self": must be a type constructor.
      ignore(self)
      0
    }
    
    // With constraints
    impl[X: Default] A for X with f(self : X) -> Int { // Error: Invalid type for "self": must be a type constructor.
      ignore(self)
      0
    }
    

建议#

When you want to define a method for a type that is not a type constructor, you may use new type to wrap the type.

pub(all) type Wrap[T] T

fn f[T](self : Wrap[T]) -> Int {
  ignore(self)
  0
}

fn g(self : Wrap[(Int) -> Unit]) -> Unit {
  (self._)(0)
}

impl[X] A for Wrap[X] with f(self : Wrap[X]) -> Int {
  ignore(self)
  0
}

However, this means you may have to wrap the value with Wrap every time you want to call the method.

If you find yourself implementing a trait for a type parameter, you may also want to consider using default implementation for the trait.

impl A with f(self : Self) -> Int {
  ignore(self)
  0
}

If you want to provide the implementation for types with specific constraints, you can add these constraints to the trait definition.

trait A: Default {
  f(Self) -> Int
}

impl A with f(self : Self) -> Int {
  ignore(self)
  0
}