@@ -5,14 +5,20 @@ use crate::scope::{ScopeTree, TypeBinding};
55use itertools:: { Itertools , izip} ;
66use ndc_core:: { StaticType , TypeSignature } ;
77use ndc_lexer:: Span ;
8- use ndc_parser:: { Binding , Expression , ExpressionLocation , ForBody , ForIteration , Lvalue , NodeId } ;
8+ use ndc_parser:: {
9+ Binding , Expression , ExpressionLocation , ForBody , ForIteration , FunctionParameter , Lvalue ,
10+ NodeId ,
11+ } ;
912
1013/// Side table holding semantic information keyed by AST node identity.
1114/// Keeps tooling-specific data (like per-expression types) out of the AST.
1215#[ derive( Debug , Default ) ]
1316pub struct AnalysisResult {
1417 /// Maps each expression node to its inferred result type.
1518 pub expr_types : HashMap < NodeId , StaticType > ,
19+ /// Inferred return types for functions without explicit annotations.
20+ /// Keyed by the FunctionDeclaration's `NodeId`.
21+ pub inferred_return_types : HashMap < NodeId , StaticType > ,
1622 /// Errors accumulated during analysis. Non-empty when the analyser
1723 /// encountered problems but was able to continue with fallback types.
1824 pub errors : Vec < AnalysisError > ,
@@ -98,7 +104,9 @@ impl Analyser {
98104 fn analyse_inner (
99105 & mut self ,
100106 ExpressionLocation {
101- expression, span, ..
107+ expression,
108+ span,
109+ id,
102110 } : & mut ExpressionLocation ,
103111 ) -> Result < StaticType , AnalysisError > {
104112 match expression {
@@ -269,12 +277,14 @@ impl Analyser {
269277 Expression :: FunctionDeclaration {
270278 name,
271279 resolved_name,
272- type_signature ,
280+ parameters ,
273281 body,
274282 return_type : return_type_slot,
275283 captures,
276284 ..
277285 } => {
286+ let type_signature = FunctionParameter :: to_type_signature ( parameters) ;
287+
278288 // Pre-register the function before analysing its body so recursive calls can
279289 // resolve the name. The return type is unknown at this point so we use Any.
280290 let pre_slot =
@@ -302,7 +312,14 @@ impl Analyser {
302312
303313 self . scope_tree . new_function_scope ( ) ;
304314 self . return_type_stack . push ( None ) ;
305- let param_types = self . resolve_parameters_declarative ( type_signature, * span) ;
315+ let param_types = self . resolve_parameters_declarative ( & type_signature, * span) ;
316+
317+ // Fill inferred_type on parameter Lvalues for LSP hints.
318+ for ( p, typ) in parameters. iter_mut ( ) . zip ( & param_types) {
319+ if let Lvalue :: Identifier { inferred_type, .. } = & mut p. lvalue {
320+ * inferred_type = Some ( typ. clone ( ) ) ;
321+ }
322+ }
306323
307324 let implicit_return = self . analyse_or_any ( body) ;
308325 let explicit_return = self . return_type_stack . pop ( ) . unwrap ( ) ;
@@ -315,8 +332,8 @@ impl Analyser {
315332 None => implicit_return,
316333 } ;
317334
318- // If there is an annotated return type, validate and use it;
319- // otherwise fall back to the inferred type.
335+ // If there is an annotated return type, validate it;
336+ // otherwise record the inferred type in the side table .
320337 if let Some ( annotated) = return_type_slot {
321338 if !inferred_return. is_subtype ( annotated) {
322339 self . emit ( AnalysisError :: mismatched_types (
@@ -326,16 +343,16 @@ impl Analyser {
326343 ) ) ;
327344 }
328345 } else {
329- * return_type_slot = Some ( inferred_return) ;
346+ self . result
347+ . inferred_return_types
348+ . insert ( * id, inferred_return. clone ( ) ) ;
330349 }
331350
351+ let effective_return = return_type_slot. clone ( ) . unwrap_or ( inferred_return) ;
352+
332353 let function_type = StaticType :: Function {
333354 parameters : Some ( param_types. clone ( ) ) ,
334- return_type : Box :: new (
335- return_type_slot
336- . clone ( )
337- . expect ( "must have a value at this point" ) ,
338- ) ,
355+ return_type : Box :: new ( effective_return) ,
339356 } ;
340357
341358 if let Some ( slot) = pre_slot {
@@ -492,10 +509,22 @@ impl Analyser {
492509 }
493510 Binding :: Resolved ( res) => self . scope_tree . get_type ( * res) . clone ( ) ,
494511
495- Binding :: Dynamic ( _) => StaticType :: Function {
496- parameters : None ,
497- return_type : Box :: new ( StaticType :: Any ) ,
498- } ,
512+ Binding :: Dynamic ( candidates) => {
513+ let return_type = candidates
514+ . iter ( )
515+ . map ( |c| self . scope_tree . get_type ( * c) . clone ( ) )
516+ . filter_map ( |t| match t {
517+ StaticType :: Function { return_type, .. } => Some ( * return_type) ,
518+ _ => None ,
519+ } )
520+ . reduce ( |a, b| a. lub ( & b) )
521+ . unwrap_or ( StaticType :: Any ) ;
522+
523+ StaticType :: Function {
524+ parameters : None ,
525+ return_type : Box :: new ( return_type) ,
526+ }
527+ }
499528 } ;
500529
501530 * resolved = binding;
0 commit comments