Verificacao de Tipos
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.
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
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:
# 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:
# 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
- Sistemas de tipos classificam valores e verificam compatibilidade de operacoes
- Static typing verifica em compile-time; dynamic typing em runtime
- O type checker percorre a AST, propaga tipos e detecta incompatibilidades
- Type inference deduz tipos sem anotacoes explicitas
- Schema validation no harness.os e o equivalente de type checking para dados
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?