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 runy 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 analyzefinaliza con código de salida0si 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 = 1int $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 = 42print($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 = 10boolean $flag = true |
Usar los tipos canónicos de Joss:int $x = 10bool $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 / 11 + 0.50.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.