Skip to content

Commit

Permalink
Remove the function head from FunctionImplementation. In the future, …
Browse files Browse the repository at this point in the history
…function implementations may exist that correspond to multiple functions (due to interning) or none (due to anonymous functions). This requires a few code beauty trade-offs, but they'll be beautified again in the future.
  • Loading branch information
Ivorforce committed Jul 16, 2024
1 parent 2a1551d commit 130bee0
Show file tree
Hide file tree
Showing 16 changed files with 86 additions and 84 deletions.
8 changes: 4 additions & 4 deletions src/interpreter/compile/compile_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ impl CompileServer {
}
}

pub fn compile_deep(&mut self, source: &Source, function: &Rc<FunctionHead>) -> RResult<Rc<Chunk>> {
let FunctionLogic::Implementation(implementation) = source.fn_logic[function].clone() else {
pub fn compile_deep(&mut self, source: &Source, function_head: &Rc<FunctionHead>) -> RResult<Rc<Chunk>> {
let FunctionLogic::Implementation(implementation) = source.fn_logic[function_head].clone() else {
return Err(RuntimeError::error("main! function was somehow internal.").to_array());
};

self.simplify.refactor.add(implementation);
self.simplify.refactor.add(Rc::clone(function_head), implementation);

self.simplify.run(source);

Expand Down Expand Up @@ -75,7 +75,7 @@ impl CompileServer {
}
}

let FunctionLogic::Implementation(implementation) = &self.simplify.refactor.fn_logic[function] else {
let FunctionLogic::Implementation(implementation) = &self.simplify.refactor.fn_logic[function_head] else {
errors.push(RuntimeError::error("main! function was somehow internal after refactor."));
return Err(errors);
};
Expand Down
4 changes: 2 additions & 2 deletions src/interpreter/compile/function_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl FunctionCompiler<'_> {
// TODO If any of these were allocated, we need to deallocate them.
// Clean up all locals that are currently allocated.
for _ in self.alloced_locals.iter().rev() {
if !self.implementation.head.interface.return_type.unit.is_void() {
if !self.implementation.interface.return_type.unit.is_void() {
self.chunk.push(OpCode::SWAP64);
}
self.chunk.push(OpCode::POP64);
Expand Down Expand Up @@ -162,6 +162,6 @@ impl FunctionCompiler<'_> {
pub fn get_variable_slot(&mut self, object: &Rc<ObjectReference>) -> i32 {
// Later, locals will be on the stack and dynamically added and removed.
// For now, all locals are allocated at function entry and deallocated at function exit.
i32::try_from(self.alloced_locals.iter().position(|l| l == object).unwrap()).unwrap() - i32::try_from(self.implementation.head.interface.parameters.len()).unwrap()
i32::try_from(self.alloced_locals.iter().position(|l| l == object).unwrap()).unwrap() - i32::try_from(self.implementation.interface.parameters.len()).unwrap()
}
}
13 changes: 2 additions & 11 deletions src/interpreter/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::error::{RResult, RuntimeError};
use crate::interpreter::data::Value;
use crate::interpreter::runtime::Runtime;
use crate::interpreter::vm::VM;
use crate::program::functions::{FunctionHead, FunctionLogic};
use crate::program::functions::FunctionHead;
use crate::program::module::Module;
use crate::transpiler::{TranspiledArtifact, Transpiler};

Expand Down Expand Up @@ -74,15 +74,6 @@ fn get_transpile_function(module: &Module) -> RResult<&Rc<FunctionHead>> {

pub fn gather_functions_logic(runtime: &Runtime, transpile_functions: &Vec<Uuid>) -> Vec<TranspiledArtifact> {
transpile_functions.iter().map(|uuid| {
let function_head = &runtime.source.fn_heads[uuid];
match &runtime.source.fn_logic[function_head] {
FunctionLogic::Implementation(implementation) => {
// TODO Why copy the implementation now?
TranspiledArtifact::Function(implementation.clone())
}
FunctionLogic::Descriptor(_) => {
panic!("Cannot transpile a function for which whe don't know an implementation!")
}
}
TranspiledArtifact::Function(Rc::clone(&runtime.source.fn_heads[uuid]))
}).collect()
}
4 changes: 2 additions & 2 deletions src/program/functions/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use std::rc::Rc;

use crate::program::allocation::ObjectReference;
use crate::program::expression_tree::ExpressionTree;
use crate::program::functions::FunctionHead;
use crate::program::functions::FunctionInterface;
use crate::program::generics::TypeForest;
use crate::program::traits::RequirementsAssumption;

#[derive(Clone)]
pub struct FunctionImplementation {
pub head: Rc<FunctionHead>,
pub interface: Rc<FunctionInterface>,

pub requirements_assumption: Box<RequirementsAssumption>,

Expand Down
10 changes: 8 additions & 2 deletions src/program/functions/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;

use display_with_options::DebugWithOptions;
use display_with_options::{DebugWithOptions, with_options};

use crate::program::functions::{FunctionCallExplicity, FunctionRepresentation, FunctionTargetType};
use crate::program::traits::{Trait, TraitBinding};
Expand Down Expand Up @@ -181,4 +181,10 @@ impl DebugWithOptions<FunctionRepresentation> for FunctionInterface {
Ok(())
// TODO Requirements?
}
}
}

impl Debug for FunctionInterface {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", with_options(self, &FunctionRepresentation::dummy()))
}
}
8 changes: 8 additions & 0 deletions src/program/functions/representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ pub struct FunctionRepresentation {


impl FunctionRepresentation {
pub fn dummy() -> FunctionRepresentation {
FunctionRepresentation {
name: "fn".into(),
target_type: FunctionTargetType::Global,
call_explicity: FunctionCallExplicity::Explicit,
}
}

pub fn new(name: &str, target_type: FunctionTargetType, explicity: FunctionCallExplicity) -> FunctionRepresentation {
FunctionRepresentation {
name: name.into(),
Expand Down
25 changes: 14 additions & 11 deletions src/refactor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,12 @@ impl Refactor {
}
}

pub fn add(&mut self, mut implementation: Box<FunctionImplementation>) {
self.explicit_functions.push(Rc::clone(&implementation.head));
self._add(implementation)
pub fn add(&mut self, head: Rc<FunctionHead>, implementation: Box<FunctionImplementation>) {
self._add(&head, implementation);
self.explicit_functions.push(head);
}

fn _add(&mut self, mut implementation: Box<FunctionImplementation>) {
let head = Rc::clone(&implementation.head);

fn _add(&mut self, head: &Rc<FunctionHead>, implementation: Box<FunctionImplementation>) {
self.fn_logic.insert(Rc::clone(&head), FunctionLogic::Implementation(implementation));
self.update_callees(&head);

Expand Down Expand Up @@ -134,7 +132,10 @@ impl Refactor {

let mut new_implementation = implementation.clone();
monomorphize_implementation(&mut new_implementation, binding);
let mono_head = Rc::clone(&new_implementation.head);
let mono_head = FunctionHead::new_static(
Rc::clone(&new_implementation.interface),
binding.function.declared_representation.clone(),
);

self.fn_optimizations.insert(Rc::clone(binding), Rc::clone(&mono_head));

Expand Down Expand Up @@ -164,11 +165,13 @@ impl Refactor {

if let Some(swizzle) = map(&mut implementation) {
// The mapper changed the interface / function ID!
assert_ne!(function, &implementation.head);
let new_head = Rc::clone(&implementation.head);
let new_head = FunctionHead::new_static(
Rc::clone(&implementation.interface),
function.declared_representation.clone(),
);;

self.invented_functions.insert(Rc::clone(&new_head));
self.fn_inline_hints.insert(Rc::clone(function), InlineHint::ReplaceCall(Rc::clone(&implementation.head), swizzle));
self.fn_inline_hints.insert(Rc::clone(function), InlineHint::ReplaceCall(Rc::clone(&new_head), swizzle));
self.fn_logic.insert(Rc::clone(&new_head), FunctionLogic::Implementation(implementation));

// Find the initial callees.
Expand All @@ -185,7 +188,7 @@ impl Refactor {
}
else {
// The function kept its interface!
assert_eq!(function, &implementation.head);
assert_eq!(&function.interface, &implementation.interface);

self.fn_logic.insert(Rc::clone(function), FunctionLogic::Implementation(implementation));
self.update_callees(function);
Expand Down
19 changes: 7 additions & 12 deletions src/refactor/locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use itertools::Itertools;

use crate::program::allocation::ObjectReference;
use crate::program::expression_tree::ExpressionOperation;
use crate::program::functions::{FunctionHead, FunctionImplementation, FunctionInterface};
use crate::program::functions::{FunctionImplementation, FunctionInterface};

pub fn swizzle_retaining_parameters(function: &FunctionImplementation, removed: &HashSet<Rc<ObjectReference>>) -> Vec<usize> {
function.parameter_locals.iter().enumerate()
Expand Down Expand Up @@ -61,17 +61,12 @@ pub fn remove_locals(implementation: &mut FunctionImplementation, removed_locals
let swizzle = swizzle_retaining_parameters(implementation, removed_locals);

// TODO We may be able to remove some generics and requirements.
let new_head = FunctionHead::new(
Rc::new(FunctionInterface {
parameters: swizzle.iter().map(|idx| implementation.head.interface.parameters[*idx].clone()).collect_vec(),
return_type: implementation.head.interface.return_type.clone(),
requirements: implementation.head.interface.requirements.clone(),
generics: implementation.head.interface.generics.clone(),
}), implementation.head.function_type.clone(),
implementation.head.declared_representation.clone(),
);

implementation.head = new_head;
implementation.interface = Rc::new(FunctionInterface {
parameters: swizzle.iter().map(|idx| implementation.interface.parameters[*idx].clone()).collect_vec(),
return_type: implementation.interface.return_type.clone(),
requirements: implementation.interface.requirements.clone(),
generics: implementation.interface.generics.clone(),
});
implementation.parameter_locals = swizzle.iter().map(|idx| implementation.parameter_locals[*idx].clone()).collect_vec();

return Some(swizzle)
Expand Down
10 changes: 1 addition & 9 deletions src/refactor/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn monomorphize_implementation(implementation: &mut FunctionImplementation,
// If monomorphize was requested on a partially generic function, we continue to
// have some requirements.
implementation.requirements_assumption = Box::new(RequirementsAssumption { conformance: Default::default() });
implementation.head = monomorphize_head(function_binding);
implementation.interface = Rc::new(map_interface_types(&function_binding.function.interface, &function_binding.requirements_fulfillment.generic_mapping));

encountered_calls
}
Expand Down Expand Up @@ -168,14 +168,6 @@ fn map_requirements_fulfillment(rc: &Rc<RequirementsFulfillment>, context: &Requ
}
}

pub fn monomorphize_head(binding: &FunctionBinding) -> Rc<FunctionHead> {
FunctionHead::new(
Rc::new(map_interface_types(&binding.function.interface, &binding.requirements_fulfillment.generic_mapping)),
binding.function.function_type.clone(),
binding.function.declared_representation.clone(),
)
}

pub fn map_variable(variable: &ObjectReference, type_forest: &TypeForest, type_replacement_map: &HashMap<Rc<Trait>, Rc<TypeProto>>) -> Rc<ObjectReference> {
Rc::new(ObjectReference {
id: variable.id.clone(),
Expand Down
4 changes: 2 additions & 2 deletions src/resolver/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::resolver::imperative::ImperativeResolver;
use crate::resolver::imperative_builder::ImperativeBuilder;
use crate::resolver::scopes;

pub fn resolve_function_body(head: Rc<FunctionHead>, body: &ast::Expression, scope: &scopes::Scope, runtime: &mut Runtime) -> RResult<Box<FunctionImplementation>> {
pub fn resolve_function_body(head: &Rc<FunctionHead>, body: &ast::Expression, scope: &scopes::Scope, runtime: &mut Runtime) -> RResult<Box<FunctionImplementation>> {
let mut scope = scope.subscope();

let granted_requirements = scope.trait_conformance.assume_granted(
Expand Down Expand Up @@ -51,7 +51,7 @@ pub fn resolve_function_body(head: Rc<FunctionHead>, body: &ast::Expression, sco
resolver.resolve_all_ambiguities()?;

Ok(Box::new(FunctionImplementation {
head,
interface: Rc::clone(&head.interface),
requirements_assumption: Box::new(RequirementsAssumption { conformance: HashMap::from_iter(granted_requirements.into_iter().map(|c| (Rc::clone(&c.binding), c))) }),
expression_tree: resolver.builder.expression_tree,
type_forest: resolver.builder.types,
Expand Down
4 changes: 2 additions & 2 deletions src/resolver/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ pub fn resolve_file(syntax: &ast::Block, scope: &scopes::Scope, runtime: &mut Ru
// Resolve function bodies
let mut errors = vec![];
for (head, pbody) in global_resolver.function_bodies {
match resolve_function_body(head, pbody.value, &global_variable_scope, runtime).and_then(|mut imp| {
match resolve_function_body(&head, pbody.value, &global_variable_scope, runtime).and_then(|mut imp| {
static_analysis::check(&mut imp)?;
Ok(imp)
}) {
Ok(implementation) => {
runtime.source.fn_logic.insert(Rc::clone(&implementation.head), FunctionLogic::Implementation(implementation));
runtime.source.fn_logic.insert(head, FunctionLogic::Implementation(implementation));
}
Err(e) => {
errors.extend(e.iter().map(|e| e.clone().in_range(pbody.position.clone())));
Expand Down
19 changes: 12 additions & 7 deletions src/transpiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Config {
}

pub enum TranspiledArtifact {
Function(Box<FunctionImplementation>)
Function(Rc<FunctionHead>)
}

pub struct Transpiler {
Expand All @@ -45,8 +45,8 @@ pub struct Transpiler {
pub struct TranspilePackage<'a> {
// In the future, this should all be accessible by monoteny code itself - including the context.
pub main_function: Option<Rc<FunctionHead>>,
pub explicit_functions: Vec<&'a FunctionImplementation>,
pub implicit_functions: Vec<&'a FunctionImplementation>,
pub explicit_functions: Vec<(Rc<FunctionHead>, &'a FunctionImplementation)>,
pub implicit_functions: Vec<(Rc<FunctionHead>, &'a FunctionImplementation)>,
pub used_native_functions: HashMap<Rc<FunctionHead>, FunctionLogicDescriptor>,
}

Expand All @@ -67,8 +67,13 @@ pub fn transpile(transpiler: Box<Transpiler>, runtime: &mut Runtime, context: &d

for artifact in transpiler.exported_artifacts {
match artifact {
TranspiledArtifact::Function(implementation) => {
refactor.add(implementation);
TranspiledArtifact::Function(function_head) => {
match &runtime.source.fn_logic[&function_head] {
FunctionLogic::Implementation(implementation) => {
refactor.add(function_head, implementation.clone());
}
FunctionLogic::Descriptor(_) => panic!("Cannot transpile a function for which whe don't know an implementation!")
}
}
}
}
Expand All @@ -94,7 +99,7 @@ pub fn transpile(transpiler: Box<Transpiler>, runtime: &mut Runtime, context: &d
let mut fn_logic = simplify.refactor.fn_logic;

let exported_functions = simplify.refactor.explicit_functions.iter()
.map(|head| fn_logic.get(head).unwrap().as_implementation())
.map(|head| Ok((Rc::clone(head), fn_logic.get(head).unwrap().as_implementation()?)))
.try_collect_many()?;
let mut implicit_functions = vec![];
let mut native_functions = HashMap::new();
Expand All @@ -103,7 +108,7 @@ pub fn transpile(transpiler: Box<Transpiler>, runtime: &mut Runtime, context: &d
// Either Refactor has it (because it invented it) or it's unchanged from source.
match fn_logic.get(&head).unwrap() {
FunctionLogic::Implementation(i) => {
implicit_functions.push(i.as_ref());
implicit_functions.push((head, i.as_ref()));
}
FunctionLogic::Descriptor(d) => {
native_functions.insert(head, d.clone());
Expand Down
18 changes: 10 additions & 8 deletions src/transpiler/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ impl Context {
// ================= Names ==================

// Names for exported functions
for implementation in transpile.explicit_functions.iter() {
for (head, implementation) in transpile.explicit_functions.iter() {
representations::find_for_function(
&mut representations.function_forms,
&mut exports_namespace,
head,
implementation,
)
}
Expand All @@ -93,7 +94,7 @@ impl Context {
// TODO We only need to export structs that are mentioned in the interfaces of exported functions.
// But the following function doesn't work for now.
// structs::find_in_interfaces(explicit_functions.iter().map(|i| &i.head), &mut structs);
structs::find_in_implementations(&transpile.explicit_functions, &transpile.used_native_functions, &mut structs);
structs::find_in_implementations(transpile.explicit_functions.iter().map(|p| *&p.1), &transpile.used_native_functions, &mut structs);
let exported_structs = structs.keys().cloned().collect_vec();
for struct_ in structs.values() {
exports_namespace.insert_name(struct_.trait_.id, struct_.trait_.name.as_str());
Expand All @@ -103,7 +104,7 @@ impl Context {

// We only really know from encountered calls which structs are left after monomorphization.
// So let's just search the encountered calls.
for implementation in transpile.explicit_functions.iter().chain(transpile.implicit_functions.iter()) {
for (head, implementation) in transpile.explicit_functions.iter().chain(transpile.implicit_functions.iter()) {
let function_namespace = internals_namespace.add_sublevel();
// Map internal variable names
for (ref_, name) in implementation.locals_names.iter() {
Expand All @@ -112,7 +113,7 @@ impl Context {
}

// Internal struct names
structs::find_in_implementations(&transpile.implicit_functions, &transpile.used_native_functions, &mut structs);
structs::find_in_implementations(transpile.implicit_functions.iter().map(|p| *&p.1), &transpile.used_native_functions, &mut structs);
let internal_structs = structs.keys().filter(|s| !exported_structs.contains(s)).collect_vec();
for type_ in internal_structs.iter() {
let struct_ = &structs[*type_];
Expand All @@ -134,10 +135,11 @@ impl Context {
}

// Internal / generated functions
for implementation in transpile.implicit_functions.iter() {
for (head, implementation) in transpile.implicit_functions.iter() {
representations::find_for_function(
&mut representations.function_forms,
&mut internals_namespace,
head,
implementation,
)
}
Expand Down Expand Up @@ -197,7 +199,7 @@ impl Context {
(&transpile.explicit_functions, true),
(&transpile.implicit_functions, false),
] {
for implementation in implementations.iter() {
for (head, implementation) in implementations.iter() {
let context = FunctionContext {
names: &names,
expressions: &implementation.expression_tree,
Expand All @@ -206,10 +208,10 @@ impl Context {
logic: &transpile.used_native_functions,
};

let transpiled = transpile_function(implementation, &context);
let transpiled = transpile_function(head, implementation, &context);

if is_exported {
module.exported_names.insert(names[&implementation.head.function_id].clone());
module.exported_names.insert(names[&head.function_id].clone());
module.exported_statements.push(transpiled);
}
else {
Expand Down
Loading

0 comments on commit 130bee0

Please sign in to comment.