Documentación oficial

Diagnósticos

Referencia técnica de Diagnósticos — Joss language and Joss Red ecosystem.

Catálogo y referencia de diagnósticos del lenguaje

Antes: Manejo de errores y excepciones, Sistema de tipos. Después: Analizador semántico AST. Índice general: Documentación de Joss.


¿Qué es un diagnóstico en Joss?

Un diagnóstico es un informe técnico estructurado emitido por las herramientas de Joss (el compilador, el analizador semántico joss analyze, el linter o el runtime defensivo) cuando se detecta una violación a las reglas sintácticas, de tipos o de seguridad del lenguaje.

A diferencia de los mensajes de error genéricos de herramientas antiguas, cada diagnóstico de Joss está diseñado siguiendo estos principios: 1. Identificador único y estable: Cada regla tiene un código inmutable (por ejemplo JOSS-TYPE-001). 2. Ubicación exacta: Archivo, línea y columna precisa donde se originó el conflicto. 3. Explicación pedagógica: Describe claramente qué regla se incumplió y por qué. 4. Sugerencia accionable: Propone la corrección canónica recomendada.

Niveles de severidad

  • error: Impide la ejecución del programa (joss run y el compilador se detienen). Representa un fallo estructural o de seguridad.
  • warning: Aviso informativo (como una variable declarada que nunca se usó o una convención de nombres desalineada). joss analyze finaliza con código de salida 0 si solo hay advertencias, permitiendo continuar la ejecución.

1. Parser, carga de proyectos y tabla de símbolos

Código Categoría Significado y Causa Ejemplo incorrecto Solución y Caso correcto
JOSS-IO-001 Entrada / Salida No se puede leer el archivo fuente en disco (permisos o ruta inexistente). joss run fantasma.joss Verificar que el archivo exista en la ruta indicada con permisos de lectura.
JOSS-PARSE-001 Sintaxis Token o estructura gramatical inválida: falta una comilla, llave o visibilidad obligatoria. class MiClase {}
func prueba() {}
Usar sintaxis canónica:
public class MiClase {}
public func prueba() {}
JOSS-SYM-001 Símbolos Variable no declarada: se intenta leer o asignar a una variable que no ha sido declarada previamente. print($variable)
$nueva = 10
Declarar la variable antes de usarla:
var $variable = "valor"
var $nueva = 10
JOSS-SYM-002 Símbolos Redeclaración de variable en el mismo ámbito léxico. int $x = 1
int $x = 2
Reasignar sin volver a declarar:
$x = 2
JOSS-SYM-003 Símbolos Función no resuelta: se invoca una función que no existe en el proyecto ni en built-ins. calcularTotal() Definir la función con public func o verificar la ortografía del nombre.
JOSS-SYM-004 Símbolos Clase no resuelta: intento de instanciar (new) una clase no declarada ni registrada. var $p = new Persona() Declarar public class Persona {} o cargar el plugin que la exponga.
JOSS-SYM-005 Símbolos Herencia inválida: la clase especificada en extends no existe o crea herencia circular. public class A extends B {} Asegurarse de que la superclase B esté declarada en el proyecto sin ciclos.
JOSS-SYM-006 Símbolos Intento de reasignar una constante inmutable. const int $MAX = 5
$MAX = 10
Si el valor debe cambiar, declararla como variable mutable: var $MAX = 5.
JOSS-SYM-007 Símbolos Interfaz no resuelta: la interfaz especificada en implements o extends no existe. public class A implements IDesconocida {} Asegurarse de declarar la interfaz o verificar su ortografía.
JOSS-SYM-008 Símbolos Herencia cíclica en interfaces: una interfaz se extiende a sí misma directa o indirectamente. public interface A extends B {}
public interface B extends A {}
Romper el ciclo de herencia entre las interfaces.
JOSS-DECL-001 Declaraciones Conflicto de nombres: dos funciones globales tienen exactamente el mismo identificador. Dos archivos con:
public func procesar() {}
Renombrar una de las dos funciones. En Joss no hay namespaces fuente por carpeta.
JOSS-DECL-002 Declaraciones Conflicto de clases: dos clases globales tienen el mismo nombre en el proyecto. Dos archivos con:
public class Usuario {}
Mantener una única declaración canónica de la clase en todo el proyecto.
JOSS-DECL-003 Declaraciones Métodos duplicados en una misma clase/interfaz, o interfaz desconocida/duplicada en implements. public func id() {}
public func id(int $x) {}
Joss no admite sobrecarga de métodos por firma; usa nombres descriptivos distintos.
JOSS-DECL-004 Declaraciones Conflicto de nombres entre tipos nominales (clase/interfaz/enum) o incumplimiento de contrato de interfaz (implements). public class MiClase implements IFigura {} (sin calcularArea()) Usar nombres únicos para cada tipo e implementar todos los métodos de la interfaz con firmas compatibles.
JOSS-DECL-005 Declaraciones Clase concreta sin implementar un método abstract heredado, o método abstract declarado en clase no abstracta. public class Perro extends Animal {} (faltando hablar()) Implementar todos los métodos abstractos en la subclase concreta o marcar la clase como abstract.
JOSS-DECL-006 Declaraciones / Migración Intento de instanciar una clase abstract con new (error), o uso de la palabra histórica let (warning en modo migración). new AnimalAbstracto()
let $valor = 1
Instancia una subclase concreta; para variables usa var, tipo explícito o mixed.
JOSS-DECL-007 Migración Una asignación creó una variable implícitamente sin declaración previa. $valor = 1 Declara antes con var, tipo explícito, mixed o const.
JOSS-DECL-008 Migración Se usó la forma histórica Init constructor(...). Init constructor() {} Migra a public func constructor() o Init().
JOSS-DECL-010 Migración Se usó nil, alias histórico de null. var $valor = nil Usa null; joss fix aplica el cambio sin tocar strings ni comentarios.
JOSS-SEM-001 Semántica Método de interfaz implementado con visibilidad no pública. private func calcularArea(): int Todos los métodos que implementan una interfaz deben ser public.
JOSS-CONST-001 Constantes Intento de modificar un campo inmutable de un record o propiedad const. $coordenada->x = 5 Los campos de un record y propiedades const son de solo lectura tras la inicialización.

2. Sistema de tipos, llamadas y accesibilidad

Código Categoría Significado y Causa Ejemplo incorrecto Solución y Caso correcto
JOSS-TYPE-001 Tipos Reasignación incompatible: se asigna un dato de tipo distinto a una variable tipada o inferida. var $edad = 20
$edad = "veinte"
Mantener el tipo homogéneo, o usar dinamismo voluntario:
mixed $edad = 20
$edad = "veinte"
JOSS-TYPE-002 Tipos Valor inicial incompatible con la anotación de tipo explícita. int $x = "texto" Proveer un valor del tipo esperado o una cadena convertible según CoerceString.
JOSS-TYPE-003 Tipos Argumento incompatible con el parámetro tipado de una función o método. public func f(int $n) {}
f("hola")
Pasar el tipo correcto o convertir el argumento antes de la llamada.
JOSS-TYPE-004 Tipos Operador aplicado a operandos no admitidos (ej. sumar texto con +). "hola" + " mundo" Para aritmética usa números; para unir texto usa el operador punto (.): "hola" . " mundo".
JOSS-TYPE-005 Tipos Tipo de clave no admitido en un mapa asociativo. {[1, 2]: "valor"} Las claves de un map deben ser de tipo string.
JOSS-TYPE-006 Tipos Tipo de índice incorrecto para una colección conocida. $arr["clave"] (en un array)
$map[true] (en un map)
Los arrays se indexan con enteros ($arr[0]); los maps con cadenas ($map["clave"]).
JOSS-TYPE-007 Tipos Intento de indexar con [...] un valor que no es indexable (ej. un entero o booleano). var $n = 42
print($n[0])
Indexar únicamente arrays, maps, cadenas o instancias compatibles.
JOSS-TYPE-008 Tipos El valor retornado por return no coincide con el tipo prometido en la firma : Tipo. public func f(): int {
return "no es int"
}
Devolver un valor compatible con la firma declarada.
JOSS-TYPE-009 Tipos Tipo de dato o clase inexistente (incluye aliases eliminados como integer, double, boolean, any, list). integer $x = 10
boolean $flag = true
Usar los tipos canónicos de Joss:
int $x = 10
bool $flag = true
JOSS-TYPE-010 Tipos Función con tipo de retorno anotado puede terminar sin ejecutar un return o throw. public func f(int $n): string {
$n > 0 ? { return "si" } : {}
}
Garantizar que todas las rutas posibles retornen un valor del tipo prometido.
JOSS-TYPE-011 Tipos Se declaró un parámetro sin tipo explícito. public func f($x) {} En Joss todos los parámetros deben declarar su tipo:
public func f(int $x) {} o public func f(mixed $x) {}
JOSS-TYPE-012 Warning Una colección mutable sin parámetros se usa como colección tipada. El alias original podría insertar valores incompatibles. array $origen = [1]
array<int> $numeros = $origen
Mantener el tipo desde la declaración o validar y copiar en el límite: array<int> $origen = [1].
JOSS-TYPE-014 Migración Una callable con nombre omitió su contrato de retorno. public func guardar() {} Declara : Tipo o : void cuando no retorna un valor.
JOSS-ARITH-003 Aritmética Una operación exige una conversión numérica implícita que puede perder precisión. 9007199254740993 / 1
1 + 0.5
0.1 + 1.00m
Usar operandos del mismo tipo y convertir explícitamente; para dinero, conservar toda la operación en decimal.
JOSS-CALL-001 Llamadas Cantidad incorrecta de argumentos respecto a los parámetros de la firma conocida. public func f(int $a, int $b) {}
f(1)
Proporcionar todos los argumentos obligatorios requeridos por la función.
JOSS-MEMBER-001 Miembros Se intenta invocar un método que no existe en la clase receptora resuelta. $usuario->metodoInexistente() Comprobar el nombre del método en la definición de la clase o en el catálogo nativo.
JOSS-ACCESS-001 Visibilidad Se intenta usar una clase o función declarada como private desde otro archivo. Llamar a una función privada de otro archivo. Declarar la función o clase como public si debe ser compartida en el proyecto.
JOSS-ACCESS-002 Visibilidad Intento de acceder a una propiedad o método private o protected fuera de su ámbito autorizado. $cuenta->saldo (siendo privado) Acceder a través de métodos públicos autorizados (getters/setters).

3. Referencias temporales (ref)

Código Categoría Significado y Causa Solución
JOSS-REF-001 Referencias Falta el marcador bilateral ref en la llamada o en la definición, o cruce ilegal a nativo/async. Si la función espera ref int $x, la llamada debe ser f(ref $x).
JOSS-REF-002 Referencias Se pasa una expresión, un literal, un campo de objeto o un índice de array como referencia. Pasar únicamente variables locales mutables directas (ref $miVariable).
JOSS-REF-003 Referencias La variable pasada como referencia es una constante inmutable (const). Una referencia muta el valor original; no puedes pasar constantes a un parámetro ref.
JOSS-REF-004 Referencias Discrepancia de tipo en la referencia (el tipo de la variable no coincide exactamente con el parámetro). Las referencias son estrictamente invariantes: un ref float exige exactamente una variable float.
JOSS-REF-005 Referencias Intento de almacenar, capturar en closure, retornar o hacer escapar una referencia. Una referencia solo vive durante la llamada; para devolver datos usa return.
JOSS-REF-006 Referencias Parámetro ref declarado con un valor por defecto. Los parámetros por referencia no admiten valores por defecto; quita el = valor.

4. Control de flujo, linter y plantillas

Código Severidad Significado y Causa Solución
JOSS-FLOW-001 Warning Código inalcanzable (dead code): instrucciones escritas después de un return incondicional. Mover las instrucciones antes del return o eliminarlas.
JOSS-FLOW-002 Warning / Error Match no exhaustivo en enum (sin cubrir todos los casos ni default), o break/continue fuera de un ciclo. Agregar los casos de enum faltantes o incluir default => ...; usar break/continue solo dentro de bucles.
JOSS-FLOW-003 Warning Acceso a miembro sobre un valor cuyo tipo todavía incluye null. Comprobar el valor contra null o usar el operador seguro ?->.
JOSS-FLOW-005 Error El bloque : { ... } de una cláusula guard no termina el flujo del callable con return o throw. Asegurarse de que el bloque guard finalice siempre con return o throw.
JOSS-LINT-001 Warning Variable local declarada pero nunca leída en el cuerpo. Utilizar la variable o retirarla para mantener el código limpio.
JOSS-SYNTAX-001 Error Error sintáctico capturado durante la fase de análisis del linter. Corregir la puntuación o estructura señalada por el parser.
JOSS-LINT-002 Error Parámetro sin tipo explícito reportado por el linter. Añadir la anotación de tipo correspondiente (int, string, mixed).
JOSS-LINT-007 Warning Desviación de convenciones de nombres del proyecto (clases en PascalCase, funciones en camelCase). Ajustar el nombre al estándar canónico.
JOSS-SEC-001 Warning Detección heurística de un posible secreto sensible escrito en texto plano (claves API, tokens). Mover el secreto al archivo de configuración de entorno (env.joss).
JOSS-VIEW-001 Error Fallo crítico al compilar o parsear una plantilla de vista HTML. Verificar el cierre de directivas (@foreach, @endforeach) y archivos incluidos.
JOSS-VIEW-SYNTAX Error Expresión de Joss mal formada dentro de una etiqueta de vista {{ ... }}. Corregir la sintaxis de la expresión embebida.
JOSS-VIEW-UNDEF Warning Variable de vista accedida sin protección ante valores indefinidos o nulos. Proteger con el operador de coalescencia nula: {{ $variable ?? 'default' }}.

5. Errores aritméticos e indexación en tiempo de ejecución

Código Categoría Operación inválida en Runtime Cómo prevenirlo
JOSS-ARITH-001 Runtime Desbordamiento de entero con signo de 64 bits (−2⁶³ a 2⁶³−1). Validar los límites antes de operar o utilizar el tipo decimal para cálculos de gran escala.
JOSS-ARITH-002 Runtime División o módulo por cero ($x / 0 o $x % 0). Comprobar que el divisor sea distinto de cero antes de ejecutar la división: ($divisor != 0) ? ($x / $divisor) : 0.0.
JOSS-INDEX-001 Runtime Índice fuera de rango: acceso a posición negativa o mayor/igual a la longitud. Verificar count($arr) antes de indexar o comprobar la existencia con array_key_exists.
JOSS-INDEX-002 Runtime Tipo de índice no compatible con la estructura de datos. Indexar arrays con números enteros y maps con cadenas de texto.

Almacenamiento (joss doctor storage)

Hallazgos de configuración emitidos por joss doctor storage. No son errores del lenguaje, pero comparten el mismo modelo de diagnóstico.

Código Qué indica Cómo resolverlo
JOSS-STORAGE-000 Comprobación superada (severidad info). Nada que hacer.
JOSS-STORAGE-001 STORAGE tiene un valor desconocido. Usar STORAGE=local o STORAGE=OCI.
JOSS-STORAGE-002 La llave privada falta, no es PEM, no es RSA o está cifrada sin OCI_PASSPHRASE. Corregir OCI_PRIVATE_KEY_PATH o generar una API key nueva.
JOSS-STORAGE-003 El fingerprint del PEM local no coincide con OCI_FINGERPRINT. Usar el PEM que corresponde al fingerprint registrado en OCI, o actualizar OCI_FINGERPRINT.
JOSS-STORAGE-004 Falta una variable OCI_* o su formato es inválido. Copiar los valores exactos desde la consola de OCI.
JOSS-STORAGE-005 OCI rechazó la autenticación (401) o no fue alcanzable. Registrar la clave pública en el usuario; si es reciente, esperar un par de minutos.
JOSS-STORAGE-006 OCI_NAMESPACE no pertenece al tenancy; la sugerencia incluye el real. Usar el namespace sugerido.
JOSS-STORAGE-007 El bucket no existe en el namespace o no hay permisos. Crear el bucket, corregir OCI_BUCKET_NAME o revisar las políticas IAM.
JOSS-STORAGE-008 ./storage no es escribible con STORAGE=local. Revisar permisos y espacio en disco.
JOSS-STORAGE-009 El proveedor (s3, aws, azure) aún no tiene driver. Usar local u OCI.

Ejemplo inválido: OCI_NAMESPACE=axghxqmjl3jf con credenciales de otro tenancy produce JOSS-STORAGE-006. Vecino válido: el mismo archivo con el namespace que indica la sugerencia.

6. Casos completos de prueba verificados

Las operaciones de canal también tienen defensas runtime estables. JOSS-CHANNEL-001 se produce al cerrar dos veces un canal o enviar después del cierre; el vecino válido es enviar mientras está abierto y cerrarlo una sola vez. JOSS-CHANNEL-002 se produce con make_chan(-1); make_chan(0) es una capacidad válida para un canal sin búfer. Estos estados pueden depender de otra tarea concurrente, así que el analyzer no puede sustituir la defensa runtime.

A continuación se presentan ejemplos ejecutables que validan formalmente la emisión de los diagnósticos y su contraparte correcta:

Tipo inexistente o alias eliminado (JOSS-TYPE-009)

integer $edad = 20

Caso corregido con el tipo canónico int:

int $edad = 20
print($edad)

Parámetro sin tipo explícito (JOSS-TYPE-011)

public func duplicar($valor) { return $valor * 2 }

Caso corregido tipando el parámetro y el retorno:

public func duplicar(int $valor): int { return $valor * 2 }
print(duplicar(3))

Reasignación con tipo incompatible (JOSS-TYPE-001)

var $edad = 20
$edad = "veinte"

Caso corregido usando dinamismo voluntario (mixed):

mixed $dato = 20
$dato = "veinte"
print($dato)

Estrechamiento inseguro de colección mutable (JOSS-TYPE-012)

La compatibilidad heredada permite la operación, pero el analyzer avisa porque ambos nombres pueden compartir la misma colección mutable.

array $origen = [1]
array<int> $numeros = $origen

Caso seguro manteniendo el tipo desde el origen:

array<int> $origen = [1]
array<int> $numeros = $origen
print($numeros[0])

Retorno ausente en rutas de flujo (JOSS-TYPE-010)

public func signo(int $n): string {
    $n > 0 ? { return "positivo" } : {}
}

Caso corregido garantizando retorno en todas las rutas posibles:

public func signo(int $n): string {
    return $n > 0 ? "positivo" : "no positivo"
}
print(signo(0))

Conversión numérica con pérdida (JOSS-ARITH-003)

var $resultado = 9007199254740993 / 1

Caso corregido conservando precisión decimal:

decimal $resultado = 9007199254740993m / 1m
print($resultado)

Match no exhaustivo en enum (JOSS-FLOW-002)

public enum Estado {
    case Activo;
    case Inactivo;
}

public func describir(Estado $e): string {
    return match ($e) {
        Estado::Activo => "activo",
    }
}

Caso corregido cubriendo exhaustivamente todos los casos del enum:

public enum Estado {
    case Activo;
    case Inactivo;
}

public func describir(Estado $e): string {
    return match ($e) {
        Estado::Activo => "activo",
        Estado::Inactivo => "inactivo",
    }
}
print(describir(Estado::Activo))

Acceso potencialmente nulo (JOSS-FLOW-003)

public class Usuario { public string $nombre = "Ada" }
public func nombre(Usuario|null $usuario): string {
    return $usuario->nombre
}

Caso corregido mediante acceso seguro:

public class Usuario { public string $nombre = "Ada" }
public func nombre(Usuario|null $usuario): string {
	return $usuario == null ? "sin usuario" : $usuario->nombre
}
print(nombre(null))

Siguiente paso

Ahora que conoces todos los diagnósticos y cómo resolverlos, puedes profundizar en cómo el analizador semántico examina el árbol de sintaxis abstracta para emitir estos códigos:

Continúa con: Analizador estático AST.