JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.44k stars 5.46k forks source link

`UndefVarError` when passing type with `TypeVar` to parametric function #55799

Closed Socob closed 23 hours ago

Socob commented 23 hours ago

When passing a type which has a TypeVar parameter to a parametric function, the result is the following unexpected UndefVarError about the function parameter:

julia> func(::Type{T}) where {T} = T
func (generic function with 1 method)

julia> func(Array{Float64, TypeVar(:N)})
ERROR: UndefVarError: `T` not defined
Stacktrace:
 [1] func(::Type{Array{Float64, N}})
   @ Main ./REPL[1]:1
 [2] top-level scope
   @ REPL[2]:1

The expected result would of course be Array{Float64, TypeVar(:N)}, not an error.

Although I’m only using exported symbols in the example above, I suspect that this might not necessarily be a supported use (?). Even if this is the case, I think at least the error should be fixed, since as it stands it’s completely misleading.


Info:

  1. The output of versioninfo():

    Julia Version 1.10.5
    Commit 6f3fdf7b362 (2024-08-27 14:19 UTC)
    Build Info:
      Official https://julialang.org/ release
    Platform Info:
      OS: Linux (x86_64-linux-gnu)
      CPU: 16 × AMD Ryzen 7 4800H with Radeon Graphics
      WORD_SIZE: 64
      LIBM: libopenlibm
      LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
    Threads: 1 default, 0 interactive, 1 GC (on 16 virtual cores)
  2. How you installed Julia: juliaup

  3. A minimal working example (MWE): see above

vtjnash commented 23 hours ago

This is correct. The value of T is only defined for well-formed types, and the TypeVar constructor does not make well-formed types. You must use func(T::Type) = T if you want to return the actual input, rather that an arbitrary transform of the input (including potentially transforming it into not having a value)

Socob commented 22 hours ago

Fair enough, but I don’t see how I’d be expected to know that T could ever end up being undefined? Like I said, a better error would be nice – I think it’d be much better if an error is thrown whenever a construction like this results in T being undefined, rather than only throwing an error when it’s used.

vtjnash commented 20 hours ago

There is no way for it to know that you would later construct a malformed type using the private TypeVar constructor

Socob commented 20 hours ago

I mean when calling the function. I don’t see why there couldn’t be an error if T is undefined at the beginning of the function?

Socob commented 20 hours ago

Also, in what sense is the TypeVar constructor private? It seems to be exported by Core?

vtjnash commented 19 hours ago

Type constructors are default private, even if the type object itself may be visible (e.g. for dispatch purposes)