Project 5 — Second Milestone#10
Open
SapoSopa wants to merge 21 commits into
Open
Conversation
…e lambda disambiguation
… for lambda expressions
…alls and correct function type checking
… functions (Milestone 2)
[TypeChecker] Check lambda and function-value calls
…t capture and add interpreter tests
[FEATURE]: Add closure snapshot capture for lexical environment restoration
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds first-class function values to MiniC, including lambda expressions, function-typed variables, and closure capture semantics in the interpreter/type-checker.
Changes:
- Extend the parser/AST to support
fn(...) -> T { ... }lambdas and calling arbitrary expressions (not just named functions). - Update the type checker to type lambdas, validate calls through function values, and allow
fn(...) -> ... f;declarations. - Update the interpreter runtime to represent and invoke closures with captured environments; add extensive test coverage and supporting docs.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ir/ast.rs | Adds Expr::Lambda / Expr::CallExpr and makes declaration initializers optional. |
| src/parser/expressions.rs | Parses lambda expressions and general call syntax callee(args). |
| src/parser/functions.rs | Adds parsing for function types fn(Ts...) -> Ret. |
| src/parser/statements.rs | Allows declarations without initializers (Type ident;). |
| src/parser/identifiers.rs | Reserves fn as a keyword. |
| src/semantic/type_checker.rs | Types lambdas, function-value calls, and function-typed decls without init. |
| src/interpreter/value.rs | Adds a Closure runtime representation with captured environment. |
| src/interpreter/exec_stmt.rs | Handles Decl without initializer at runtime. |
| src/interpreter/eval_expr.rs | Evaluates lambdas to closures and supports calling function values. |
| tests/* | Adds new parser/type-check/integration/runtime tests for function types, lambdas, and closures. |
| docs/semantics-first-class-fn.md | Documents intended closure semantics and function-value behavior. |
| docs/09-projects.md | Updates project assignment table and milestone date text. |
Comments suppressed due to low confidence (1)
src/interpreter/eval_expr.rs:1
eval_exprnow supports calling function values viaeval_call_value(...), buteval_call(...)is still limited toenv.get_function(name)and doesn’t delegate to the new logic. Since statement-level calls (Statement::Call) still go througheval_call, calling a function stored in a variable (e.g.fn(int)->int f; f = ...; f(1);) will not work consistently. Makeeval_callfetch the callee from the same value environment asExpr::Calldoes (e.g.,env.get(name).cloned()) and then delegate toeval_call_value(callee, args, env, Some(name)), so both statement calls and expression calls share the same behavior.
//! Expression evaluator for the MiniC interpreter.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+107
to
+123
| /// Chamada de função por expressão: chmd(args) | ||
| /// apenas para não mexer em Call, mas depois podemos mesclar os dois (Call pode ser um caso especial de CallExpr onde callee é um Ident). | ||
| /// Ex.: 'f(42)', '(funçãolambda)(42)', etc.) | ||
| CallExpr { | ||
| chmd: Box<ExprD<Ty>>, | ||
| args: Vec<ExprD<Ty>>, | ||
| }, | ||
|
|
||
| /// Função Lambda: `fn(params) -> return_tipo { crp }` | ||
| /// regra pra não ficar ambiguo: | ||
| /// 'fn(...) -> ...' é tipo, ou seja 'Type::Fun' | ||
| /// 'fn(...) -> ... { ... }' é expressão, ou seja 'Expr::Lambda' | ||
| Lambda { | ||
| params: Vec<Param>, | ||
| return_tipo: Type, | ||
| crp: Box<StatementD<Ty>>, | ||
| }, |
Comment on lines
+331
to
+374
| fn type_of_function_call( | ||
| callee_ty: &Type, | ||
| args: &[CheckedExpr], | ||
| label: &str, | ||
| ) -> Result<Type, TypeError> { | ||
| match callee_ty { | ||
| Type::Fun(param_tys, return_ty) => { | ||
| if args.len() != param_tys.len() { | ||
| return Err(TypeError::new(format!( | ||
| "{} expects {} arguments, got {}", | ||
| label, | ||
| param_tys.len(), | ||
| args.len() | ||
| ))); | ||
| } | ||
|
|
||
| for (i, (arg, param_ty)) in args.iter().zip(param_tys.iter()).enumerate() { | ||
| if !types_compatible(&arg.ty, param_ty) { | ||
| return Err(TypeError::new(format!( | ||
| "argument {} to {}: expected {:?}, got {:?}", | ||
| i + 1, | ||
| label, | ||
| param_ty, | ||
| arg.ty | ||
| ))); | ||
| } | ||
| } | ||
|
|
||
| Ok((**return_ty).clone()) | ||
| } | ||
|
|
||
| other => { | ||
| if label == "function value" { | ||
| Err(TypeError::new("attempting to call a non-function value")) | ||
| } | ||
| else { | ||
| Err(TypeError::new(format!( | ||
| "{} is not a function, got {:?}", | ||
| label, other | ||
| ))) | ||
| } | ||
| } | ||
| } | ||
| } |
Comment on lines
+52
to
+53
| Decisão sobre declarações sem inicializador | ||
| - Não declarar uma variável de tipo função sem init (a não ser que queiram mais trabalho, ai só avisar no grupo pra gente rever isso). |
Comment on lines
+694
to
+706
| (Type::Fun(params_a, ret_a), Type::Fun(params_b, ret_b)) => { | ||
| if params_a.len() != params_b.len() { | ||
| return false; | ||
| } | ||
|
|
||
| for (a, b) in params_a.iter().zip(params_b.iter()) { | ||
| if a != b { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| ret_a == ret_b | ||
| }, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
##Grupo:
Resumo
Este PR organiza a base da Milestone 2 do Projeto 5, formalizando a semântica de funções de primeira classe e closures, e adicionando testes-esqueleto mais completos para a divisão de trabalho do grupo.
O que mudou
Objetivo
Deixar explícito o contrato entre type checker e interpreter.