Monomorfización de Genéricos

Archivo: src/monomorph.rs (605 líneas)

¿Por qué existe?

Detecta todas las instanciaciones concretas de genéricos en un programa y genera versiones especializadas para cada tipo concreto. Esto elimina el dispatch dinámico (sin boxing ni vtables en las llamadas) y habilita optimizaciones como inlining y dead code elimination sobre cada versión tipada. Es la técnica clásica de C++/Rust aplicada al compilador de Forja.

Ejemplo

clase Caja<T> { valor: T }
funcion obtener<T>(c: Caja<T>) -> T { retornar c.valor }

variable c1 = nueva Caja<Entero> { valor: 42 }
variable c2 = nueva Caja<Texto> { valor: "hola" }

Se genera:

Estructuras clave

ComponenteDescripción
ConcreteTypeRepresenta un tipo concreto monomorfizable: Entero, Decimal, Texto, Booleano, Nulo, Exacto, Clase(String), Arreglo, Resultado, Opcion
GenericInstantiationInstanciación detectada: nombre original, type_args (parámetro → tipo concreto) y specialized_name resultante
MonomorphizerRecolector y generador: registros de funciones/clases genéricas, instanciaciones y declaraciones especializadas
FuncionGenerica / ClaseGenericaDefiniciones genéricas extraídas (parámetros de tipo, parámetros, cuerpo / campos y métodos)

Pipeline (3 fases)

FaseMétodoDescripción
1 — Extracciónextract_genericsRecorre las declaraciones y guarda funciones (parametros_tipo no vacío) y clases genéricas
2 — Recoleccióncollect_instantiationsRecorre variables, cuerpos de funciones y métodos; detecta llamadas a funciones genéricas e instanciaciones de clases
3 — EspecializaciónspecializeGenera una Declaracion por instanciación con parámetros de tipo reemplazados por tipos concretos

Inferencia de tipos

Para funciones, infer_type_args_for_fn recorre cada parámetro de tipo, encuentra el primer parámetro de la función que lo usa (tipo_usa_parametro) y extrae el tipo concreto del argumento correspondiente en la llamada. Para clases, infer_type_args_for_class infiere del primer argumento (si hay un solo parámetro de tipo) o mapea por posición. infer_concrete_from_expr resuelve directamente literales (número, decimal, texto, booleano, nulo, exacto, arreglos por su primer elemento); las variables requieren el type checker y retornan None.

Generación de nombres especializados

ConcreteType::name() produce identificadores legibles: Arr_Entero para arreglos, Result_A_B para resultados, Opt_T para opciones. El nombre especializado de una instanciación se forma como nombre_tipo1_tipo2 (ej. obtener_Entero), y se evitan duplicados comparando specialized_name.

Cómo se integra

El monomorphizer corre como una pasada sobre el AST (ast::Programa) antes de la compilación a bytecode: reemplaza los tipos Parametro por los concretos en parámetros, retorno y campos con replace_type_params, y devuelve las declaraciones especializadas con get_specializations para que el resto del pipeline las compile como funciones/clases normales.

💡 ConcreteType::from_tipo no monomorfiza tipos función ni RasgoObjeto, y los Parametro sin resolver retornan None: la monomorfización solo actúa sobre tipos concretos.
⚠️ El cuerpo de la función especializada se clona sin reemplazo de tipos en su interior (simplificación documentada); la inferencia completa de expresiones de variables requiere el type checker.