College Online
0%

Verificacao de Tipos

Modulo 4 · Aula 3 ~20 min de leitura Nivel: Intermediario

Video da aula estara disponivel em breve

Sistemas de Tipos

Um sistema de tipos e um conjunto de regras que atribui tipos a construcoes do programa e verifica que operacoes sao compatilveis com esses tipos. O type checker percorre a AST, atribui tipos a cada expressao, e verifica compatibilidade.

Diagrama
Static Typing (C, Java, Rust)        Dynamic Typing (Python, Ruby, JS)
+----------------------------+       +----------------------------+
| Tipos verificados em        |       | Tipos verificados em        |
| COMPILE-TIME                |       | RUNTIME                     |
| Erros antes de executar     |       | Erros durante execucao      |
| Performance: sem checks     |       | Performance: checks em      |
|   em runtime                |       |   cada operacao              |
| Exemplos: int x = "hello";  |       | Exemplos: x = "hello"       |
|   -> ERRO de compilacao     |       |   x + 1 -> TypeError runtime |
+----------------------------+       +----------------------------+

Strong Typing (Python, Rust)         Weak Typing (C, JavaScript)
- Nao permite conversoes implicitas   - Conversoes implicitas
  perigosas                            "5" + 3 -> "53" (JS)
- TypeError em operacoes invalidas     int* cast para void* (C)

Type Checking: Regras de Tipo

Python
class TypeChecker(ASTVisitor):
    """Verificador de tipos para expressoes."""

    def __init__(self, symbol_table):
        self.symbols = symbol_table
        self.errors = []

    def visit_NumberLit(self, node):
        if isinstance(node.value, int):
            return 'int'
        return 'float'

    def visit_StringLit(self, node):
        return 'string'

    def visit_Identifier(self, node):
        info = self.symbols.lookup(node.name)
        return info['type']

    def visit_BinOp(self, node):
        left_type = self.visit(node.left)
        right_type = self.visit(node.right)

        # Regras de tipo para operacoes aritmeticas
        if node.op in ('+', '-', '*', '/'):
            if left_type == 'string' or right_type == 'string':
                if node.op == '+' and left_type == 'string' and right_type == 'string':
                    return 'string'  # concatenacao
                self.errors.append(
                    f"Operacao '{node.op}' invalida entre {left_type} e {right_type}"
                )
                return 'error'
            # Promocao de tipo: int op float -> float
            if 'float' in (left_type, right_type):
                return 'float'
            return 'int'

        # Comparacoes retornam bool
        if node.op in ('==', '!=', '<', '>', '<=', '>='):
            return 'bool'

        return 'error'

    def visit_Assignment(self, node):
        value_type = self.visit(node.value)
        target_info = self.symbols.lookup(node.target.name)
        if target_info['type'] != value_type and value_type != 'error':
            # Verificar compatibilidade
            if not self.is_compatible(target_info['type'], value_type):
                self.errors.append(
                    f"Nao e possivel atribuir {value_type} a {target_info['type']}"
                )
        return value_type

    def is_compatible(self, target, source):
        # int pode ser promovido a float
        if target == 'float' and source == 'int':
            return True
        return target == source

Inferencia de Tipos

Type inference permite ao compilador deduzir tipos sem anotacoes explicitas. Algoritmos como Hindley-Milner (usado em Haskell, OCaml, Rust parcialmente) unificam restricoes de tipo:

Python
# Inferencia de tipos simplificada
# Dado: let x = 42         -> infere x: int
# Dado: let y = x + 3.14   -> infere y: float (promocao)
# Dado: let z = "hello"    -> infere z: string

def infer_type(node, env):
    """Inferencia de tipos por restricoes."""
    if isinstance(node, NumberLit):
        return 'int' if isinstance(node.value, int) else 'float'
    elif isinstance(node, StringLit):
        return 'string'
    elif isinstance(node, Identifier):
        if node.name in env:
            return env[node.name]
        raise NameError(f"Variavel '{node.name}' nao definida")
    elif isinstance(node, BinOp):
        lt = infer_type(node.left, env)
        rt = infer_type(node.right, env)
        if lt == 'float' or rt == 'float':
            return 'float'
        return 'int'
    elif isinstance(node, Assignment):
        val_type = infer_type(node.value, env)
        env[node.target.name] = val_type  # registra o tipo inferido
        return val_type

No harness.os

O harness.os precisa validar schemas de knowledge chunks — isso e analogo a type checking. Cada chunk tem campos obrigatorios com tipos esperados:

Python
# Schema validator para knowledge chunks do harness.os
# Analogo a type checking em compiladores

KNOWLEDGE_SCHEMA = {
    'title':   {'type': 'string', 'required': True},
    'domain':  {'type': 'string', 'required': True,
               'enum': ['build', 'product', 'operations', 'domain']},
    'concern': {'type': 'string', 'required': True,
               'enum': ['relational', 'governance', 'causal',
                       'metacognitive', 'security']},
    'content': {'type': 'string', 'required': True},
    'tokens':  {'type': 'int', 'required': False},
}

def validate_knowledge(chunk, schema=KNOWLEDGE_SCHEMA):
    """Type-check um knowledge chunk contra o schema."""
    errors = []
    for field, rules in schema.items():
        if rules['required'] and field not in chunk:
            errors.append(f"Campo obrigatorio ausente: '{field}'")
            continue
        if field in chunk:
            value = chunk[field]
            expected = rules['type']
            actual = type(value).__name__
            if expected == 'string' and not isinstance(value, str):
                errors.append(f"'{field}': esperado string, achei {actual}")
            if 'enum' in rules and value not in rules['enum']:
                errors.append(f"'{field}': valor '{value}' nao e valido. "
                              f"Opcoes: {rules['enum']}")
    return errors

# Testar
chunk_ok = {'title': 'Commit Hygiene', 'domain': 'build',
            'concern': 'governance', 'content': '...'}
print(validate_knowledge(chunk_ok))  # []

chunk_bad = {'title': 'Bad Chunk', 'domain': 'invalid'}
print(validate_knowledge(chunk_bad))
# ["'domain': valor 'invalid' nao e valido...",
#  "Campo obrigatorio ausente: 'concern'", ...]

Resumo

Exercicio

Construa um schema validator para knowledge chunks do harness.os que verifique: campos obrigatorios (title, domain, concern, content), tipos de dados (string, int), valores validos para enums (domain, concern), e relacoes entre campos. Teste com chunks validos e invalidos.

Verifique seu entendimento

Quando o compilador encontra a expressao 3 + 2.5, qual operacao o type checker realiza?

  • Rejeita a expressao porque os tipos sao diferentes
  • Promocao de tipo: converte o int 3 para float 3.0 e o resultado e float
  • Converte 2.5 para int 2 e o resultado e int
  • Deixa para resolver em runtime