Skip to content

[12/15] Unsupported-type refusals surface as internal dumps instead of clean errors #133

Description

@mns-nordicals

What happens

quickr correctly refuses character values and unsupported complex
operations, but the refusals are unreadable:

quick(function(x) { declare(type(x = character(1))); x })("a")
#> Error: unrecognized kind: <quickr::Variable> @ mode : chr "character"
#>   @ dims :List of 1 .. $ : int 1 @ name : chr "x" ...   (an S7 dump)

fn <- function(x, y) {
  declare(type(x = complex(1)), type(y = complex(1)))
  x < y
}
quick(fn)(1i, 2i)
#> Error: Compilation Error
#>   ... f2_fsub.f90:13:10: out_ = (x < y)
#>   Compiler Error: COMPLEX quantities cannot be compared at (1) ...

x %% y on complex operands fails the same way (a raw gfortran dump).
R errors in all three cases (invalid comparison with complex values,
unimplemented complex operation) — the refusals are right, the
diagnostics are not.

Why it happens

Character declarations pass type_call_to_var() (R/sizes.R) untouched
and only die when the manifest generator finds no Fortran kind for the
mode — stop("unrecognized kind: ", format(var)) prints the whole S7
object. Complex order comparisons and complex %% are never
intercepted at all: the operands promote to complex and gfortran
rejects the emitted < / modulo().

Complex operands flow into the real BLAS/LAPACK routines (found in
external review) — worse than an ugly error, this is a silent wrong
answer. The linalg paths cast logical/integer operands to double and
pass complex through untouched, so dgemm/dgesv read complex storage
as reals:

complex_dot <- quick(function(x, y) {
  declare(type(x = complex(2)), type(y = complex(2)))
  x %*% y
})
complex_dot(c(1 + 1i, 2 + 0i), c(3 + 0i, 4 + 1i))
#> matrix(3), typeof double
#> R: matrix(11 + 5i), typeof complex

The 3 is c(1, 1) . c(3, 0): dgemm reads the interleaved complex
storage as a plain double array, so the real and imaginary halves of the
first element become the two elements of a length-2 real vector. The
answer is arbitrary, not a real-part projection.

Expected behavior

A mode or operation with no Fortran translation should be a clean
compile-time error naming what is unsupported: character declarations
refused at declare(), complex ordering and complex %% refused at
the operator with R's own error messages. Complex equality (==/!=)
keeps working — R supports it. Complex operands anywhere on the
linear-algebra surface (%*%, crossprod, solve, chol, svd, outer, ...)
are refused at compile time — quickr's lowerings are double-only; the
mode-preserving standalone t() keeps working.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions