Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / call_graph.rs
18 kB 548 lines
1//! Graphs that represent the relationships between entities in a Gleam module, 2//! such as module functions or constants. 3 4#[cfg(test)] 5mod into_dependency_order_tests; 6 7use crate::{ 8 Result, 9 ast::{ 10 AssignName, BitArrayOption, ClauseGuard, Constant, Pattern, SrcSpan, Statement, 11 UntypedClauseGuard, UntypedExpr, UntypedFunction, UntypedModuleConstant, UntypedPattern, 12 UntypedStatement, 13 }, 14 type_::Error, 15}; 16use itertools::Itertools; 17use petgraph::stable_graph::NodeIndex; 18use petgraph::{Directed, stable_graph::StableGraph}; 19 20#[derive(Debug, Default)] 21struct CallGraphBuilder<'a> { 22 names: im::HashMap<&'a str, Option<(NodeIndex, SrcSpan)>>, 23 graph: StableGraph<(), (), Directed>, 24 current_function: NodeIndex, 25} 26 27#[derive(Debug, Clone, PartialEq, Eq)] 28pub enum CallGraphNode { 29 Function(UntypedFunction), 30 31 ModuleConstant(UntypedModuleConstant), 32} 33 34impl<'a> CallGraphBuilder<'a> { 35 fn into_graph(self) -> StableGraph<(), (), Directed> { 36 self.graph 37 } 38 39 /// Add each function to the graph, storing the index of the node under the 40 /// name of the function. 41 fn register_module_function_existence( 42 &mut self, 43 function: &'a UntypedFunction, 44 ) -> Result<(), Error> { 45 let (_, name) = function 46 .name 47 .as_ref() 48 .expect("A module's function must be named"); 49 let location = function.location; 50 51 let index = self.graph.add_node(()); 52 let previous = self.names.insert(name, Some((index, location))); 53 54 if let Some(Some((_, previous_location))) = previous { 55 return Err(Error::DuplicateName { 56 location_a: location, 57 location_b: previous_location, 58 name: name.clone(), 59 }); 60 } 61 Ok(()) 62 } 63 64 /// Add each constant to the graph, storing the index of the node under the 65 /// name of the constant. 66 fn register_module_const_existence( 67 &mut self, 68 constant: &'a UntypedModuleConstant, 69 ) -> Result<(), Error> { 70 let name = &constant.name; 71 let location = constant.location; 72 73 let index = self.graph.add_node(()); 74 let previous = self.names.insert(name, Some((index, location))); 75 76 if let Some(Some((_, previous_location))) = previous { 77 return Err(Error::DuplicateName { 78 location_a: location, 79 location_b: previous_location, 80 name: name.clone(), 81 }); 82 } 83 Ok(()) 84 } 85 86 fn register_references_constant(&mut self, constant: &'a UntypedModuleConstant) { 87 self.current_function = self 88 .names 89 .get(constant.name.as_str()) 90 .expect("Constant must already have been registered as existing") 91 .expect("Constant must not be shadowed at module level") 92 .0; 93 self.constant(&constant.value); 94 } 95 96 fn register_references(&mut self, function: &'a UntypedFunction) { 97 let names = self.names.clone(); 98 99 self.current_function = self 100 .names 101 .get( 102 function 103 .name 104 .as_ref() 105 .map(|(_, name)| name.as_str()) 106 .expect("A module's function must be named"), 107 ) 108 .expect("Function must already have been registered as existing") 109 .expect("Function must not be shadowed at module level") 110 .0; 111 for name in function 112 .arguments 113 .iter() 114 .flat_map(|a| a.get_variable_name()) 115 { 116 self.define(name); 117 } 118 self.statements(&function.body); 119 self.names = names; 120 } 121 122 fn referenced(&mut self, name: &str) { 123 // If we don't know what the target is then it's either a programmer 124 // error to be detected later, or it's not a module function and as such 125 // is not a value we are tracking. 126 let Some(target) = self.names.get(name) else { 127 return; 128 }; 129 130 // If the target is known but registered as None then it's local value 131 // that shadows a module function. 132 let Some((target, _)) = target else { return }; 133 134 _ = self.graph.add_edge(self.current_function, *target, ()); 135 } 136 137 fn statements(&mut self, statements: &'a [UntypedStatement]) { 138 let names = self.names.clone(); 139 for statement in statements { 140 self.statement(statement); 141 } 142 self.names = names; 143 } 144 145 fn statement(&mut self, statement: &'a UntypedStatement) { 146 match statement { 147 Statement::Expression(expression) => { 148 self.expression(expression); 149 } 150 Statement::Assignment(assignment) => { 151 self.expression(&assignment.value); 152 self.pattern(&assignment.pattern); 153 } 154 Statement::Use(use_) => { 155 self.expression(&use_.call); 156 for assignment in &use_.assignments { 157 self.pattern(&assignment.pattern); 158 } 159 } 160 Statement::Assert(assert) => { 161 self.expression(&assert.value); 162 } 163 }; 164 } 165 166 fn expression(&mut self, expression: &'a UntypedExpr) { 167 match expression { 168 UntypedExpr::Int { .. } 169 | UntypedExpr::Float { .. } 170 | UntypedExpr::String { .. } 171 | UntypedExpr::Placeholder { .. } => (), 172 173 UntypedExpr::Todo { message, .. } => { 174 if let Some(msg_expr) = message { 175 self.expression(msg_expr) 176 } 177 } 178 179 UntypedExpr::Panic { message, .. } => { 180 if let Some(msg_expr) = message { 181 self.expression(msg_expr) 182 } 183 } 184 185 UntypedExpr::Echo { 186 expression, 187 location: _, 188 } => { 189 if let Some(expression) = expression { 190 self.expression(expression); 191 } 192 } 193 194 // Aha! A variable is being referenced. 195 UntypedExpr::Var { name, .. } => { 196 self.referenced(name); 197 } 198 199 UntypedExpr::Call { fun, arguments, .. } => { 200 self.expression(fun); 201 for argument in arguments { 202 self.expression(&argument.value); 203 } 204 } 205 206 UntypedExpr::PipeLine { expressions } => { 207 for expression in expressions { 208 self.expression(expression); 209 } 210 } 211 212 UntypedExpr::Tuple { elements, .. } => { 213 for expression in elements { 214 self.expression(expression); 215 } 216 } 217 218 UntypedExpr::Block { statements, .. } => { 219 let names = self.names.clone(); 220 self.statements(statements); 221 self.names = names; 222 } 223 224 UntypedExpr::BinOp { left, right, .. } => { 225 self.expression(left); 226 self.expression(right); 227 } 228 229 UntypedExpr::List { elements, tail, .. } => { 230 for element in elements { 231 self.expression(element); 232 } 233 if let Some(tail) = tail { 234 self.expression(tail); 235 } 236 } 237 238 UntypedExpr::NegateInt { 239 value: expression, .. 240 } 241 | UntypedExpr::NegateBool { 242 value: expression, .. 243 } 244 | UntypedExpr::TupleIndex { 245 tuple: expression, .. 246 } 247 | UntypedExpr::FieldAccess { 248 container: expression, 249 .. 250 } => { 251 self.expression(expression); 252 } 253 254 UntypedExpr::BitArray { segments, .. } => { 255 for segment in segments { 256 self.expression(&segment.value); 257 for option in &segment.options { 258 if let BitArrayOption::Size { value, .. } = option { 259 self.expression(value); 260 } 261 } 262 } 263 } 264 265 UntypedExpr::RecordUpdate { 266 record, arguments, .. 267 } => { 268 self.expression(&record.base); 269 for argument in arguments { 270 self.expression(&argument.value); 271 } 272 } 273 274 UntypedExpr::Fn { 275 arguments, body, .. 276 } => { 277 let names = self.names.clone(); 278 for argument in arguments { 279 if let Some(name) = argument.names.get_variable_name() { 280 self.define(name) 281 } 282 } 283 self.statements(body); 284 self.names = names; 285 } 286 287 UntypedExpr::Case { 288 subjects, clauses, .. 289 } => { 290 for subject in subjects { 291 self.expression(subject); 292 } 293 for clause in clauses.as_deref().unwrap_or_default() { 294 let names = self.names.clone(); 295 for pattern in &clause.pattern { 296 self.pattern(pattern); 297 } 298 if let Some(guard) = &clause.guard { 299 self.guard(guard); 300 } 301 self.expression(&clause.then); 302 self.names = names; 303 } 304 } 305 } 306 } 307 308 fn pattern(&mut self, pattern: &'a UntypedPattern) { 309 match pattern { 310 Pattern::Discard { .. } 311 | Pattern::Int { .. } 312 | Pattern::Float { .. } 313 | Pattern::String { .. } 314 | Pattern::StringPrefix { 315 right_side_assignment: AssignName::Discard(_), 316 .. 317 } 318 | Pattern::Invalid { .. } => (), 319 320 Pattern::StringPrefix { 321 right_side_assignment: AssignName::Variable(name), 322 .. 323 } 324 | Pattern::Variable { name, .. } => { 325 self.define(name); 326 } 327 328 Pattern::Tuple { 329 elements: patterns, .. 330 } => { 331 for pattern in patterns { 332 self.pattern(pattern); 333 } 334 } 335 336 Pattern::List { elements, tail, .. } => { 337 for element in elements { 338 self.pattern(element); 339 } 340 if let Some(tail) = tail { 341 self.pattern(tail); 342 } 343 } 344 345 Pattern::VarUsage { name, .. } => { 346 self.referenced(name); 347 } 348 349 Pattern::Assign { name, pattern, .. } => { 350 self.define(name); 351 self.pattern(pattern); 352 } 353 354 Pattern::Constructor { arguments, .. } => { 355 for argument in arguments { 356 self.pattern(&argument.value); 357 } 358 } 359 360 Pattern::BitArray { segments, .. } => { 361 for segment in segments { 362 for option in &segment.options { 363 self.bit_array_option(option, |s, p| s.pattern(p)); 364 } 365 self.pattern(&segment.value); 366 } 367 } 368 } 369 } 370 371 fn define(&mut self, name: &'a str) { 372 _ = self.names.insert(name, None); 373 } 374 375 fn bit_array_option<T>( 376 &mut self, 377 option: &'a BitArrayOption<T>, 378 process: impl Fn(&mut Self, &'a T), 379 ) { 380 match option { 381 BitArrayOption::Big { .. } 382 | BitArrayOption::Bytes { .. } 383 | BitArrayOption::Bits { .. } 384 | BitArrayOption::Float { .. } 385 | BitArrayOption::Int { .. } 386 | BitArrayOption::Little { .. } 387 | BitArrayOption::Native { .. } 388 | BitArrayOption::Signed { .. } 389 | BitArrayOption::Unit { .. } 390 | BitArrayOption::Unsigned { .. } 391 | BitArrayOption::Utf16 { .. } 392 | BitArrayOption::Utf16Codepoint { .. } 393 | BitArrayOption::Utf32 { .. } 394 | BitArrayOption::Utf32Codepoint { .. } 395 | BitArrayOption::Utf8 { .. } 396 | BitArrayOption::Utf8Codepoint { .. } => (), 397 398 BitArrayOption::Size { value: pattern, .. } => { 399 process(self, pattern); 400 } 401 } 402 } 403 404 fn guard(&mut self, guard: &'a UntypedClauseGuard) { 405 match guard { 406 ClauseGuard::Equals { left, right, .. } 407 | ClauseGuard::NotEquals { left, right, .. } 408 | ClauseGuard::GtInt { left, right, .. } 409 | ClauseGuard::GtEqInt { left, right, .. } 410 | ClauseGuard::LtInt { left, right, .. } 411 | ClauseGuard::LtEqInt { left, right, .. } 412 | ClauseGuard::GtFloat { left, right, .. } 413 | ClauseGuard::GtEqFloat { left, right, .. } 414 | ClauseGuard::LtFloat { left, right, .. } 415 | ClauseGuard::LtEqFloat { left, right, .. } 416 | ClauseGuard::AddInt { left, right, .. } 417 | ClauseGuard::AddFloat { left, right, .. } 418 | ClauseGuard::SubInt { left, right, .. } 419 | ClauseGuard::SubFloat { left, right, .. } 420 | ClauseGuard::MultInt { left, right, .. } 421 | ClauseGuard::MultFloat { left, right, .. } 422 | ClauseGuard::DivInt { left, right, .. } 423 | ClauseGuard::DivFloat { left, right, .. } 424 | ClauseGuard::RemainderInt { left, right, .. } 425 | ClauseGuard::Or { left, right, .. } 426 | ClauseGuard::And { left, right, .. } => { 427 self.guard(left); 428 self.guard(right); 429 } 430 431 ClauseGuard::Not { expression, .. } => self.guard(expression), 432 433 ClauseGuard::Var { name, .. } => self.referenced(name), 434 435 ClauseGuard::TupleIndex { tuple, .. } => self.guard(tuple), 436 437 ClauseGuard::FieldAccess { container, .. } => self.guard(container), 438 439 ClauseGuard::ModuleSelect { module_name, .. } => self.referenced(module_name), 440 441 ClauseGuard::Constant(constant) => self.constant(constant), 442 } 443 } 444 445 fn constant(&mut self, constant: &'a Constant<(), ()>) { 446 match constant { 447 Constant::Int { .. } 448 | Constant::Float { .. } 449 | Constant::String { .. } 450 | Constant::Invalid { .. } 451 | Constant::Var { 452 module: Some(_), .. 453 } => (), 454 455 Constant::List { elements, .. } | Constant::Tuple { elements, .. } => { 456 for element in elements { 457 self.constant(element); 458 } 459 } 460 461 Constant::Record { args, .. } => { 462 for arg in args { 463 self.constant(&arg.value); 464 } 465 } 466 467 Constant::Var { 468 module: None, name, .. 469 } => self.referenced(name), 470 471 Constant::BitArray { segments, .. } => { 472 for segment in segments { 473 for option in &segment.options { 474 self.bit_array_option(option, |s, c| s.constant(c)); 475 } 476 self.constant(&segment.value); 477 } 478 } 479 480 Constant::StringConcatenation { left, right, .. } => { 481 self.constant(left); 482 self.constant(right); 483 } 484 } 485 } 486} 487 488/// Determine the order in which functions and constants should be compiled and if any 489/// mutually recursive functions need to be compiled together. 490/// 491pub fn into_dependency_order( 492 functions: Vec<UntypedFunction>, 493 constants: Vec<UntypedModuleConstant>, 494) -> Result<Vec<Vec<CallGraphNode>>, Error> { 495 let mut grapher = CallGraphBuilder::default(); 496 497 for function in &functions { 498 grapher.register_module_function_existence(function)?; 499 } 500 501 for constant in &constants { 502 grapher.register_module_const_existence(constant)?; 503 } 504 505 // Build the call graph between the module functions. 506 for function in &functions { 507 grapher.register_references(function); 508 } 509 510 for constant in &constants { 511 grapher.register_references_constant(constant); 512 } 513 514 // Consume the grapher to get the graph 515 let graph = grapher.into_graph(); 516 517 // Determine the order in which the functions should be compiled by looking 518 // at which other functions they depend on. 519 let indices = crate::graph::into_dependency_order(graph); 520 521 // We got node indices back, so we need to map them back to the functions 522 // they represent. 523 // We wrap them each with `Some` so we can use `.take()`. 524 let mut definitions = functions 525 .into_iter() 526 .map(CallGraphNode::Function) 527 .chain(constants.into_iter().map(CallGraphNode::ModuleConstant)) 528 .map(Some) 529 .collect_vec(); 530 531 let ordered = indices 532 .into_iter() 533 .map(|level| { 534 level 535 .into_iter() 536 .map(|index| { 537 definitions 538 .get_mut(index.index()) 539 .expect("Index out of bounds") 540 .take() 541 .expect("Function already taken") 542 }) 543 .collect_vec() 544 }) 545 .collect_vec(); 546 547 Ok(ordered) 548}