Changeset - ac0d6a5fb496
[Not reviewed]
0 3 0
mh - 3 years ago 2022-02-24 08:01:21
contact@maxhenger.nl
WIP: Adding monomorphs to AST
3 files changed with 72 insertions and 51 deletions:
0 comments (0 inline, 0 general)
src/protocol/ast.rs
Show inline comments
 
@@ -5,6 +5,7 @@ use std::ops::{Index, IndexMut};
 
use super::arena::{Arena, Id};
 
use crate::collections::StringRef;
 
use crate::protocol::input_source::InputSpan;
 
use crate::protocol::TypeId;
 

	
 
/// Helper macro that defines a type alias for a AST element ID. In this case 
 
/// only used to alias the `Id<T>` types.
 
@@ -1015,6 +1016,18 @@ pub enum ProcedureKind {
 
    Composite,
 
}
 

	
 
/// Monomorphed instantiation of a procedure (or the sole instantiation of a
 
/// non-polymorphic procedure).
 
pub struct ProcedureDefinitionMonomorph {
 
    pub argument_types: Vec<TypeId>,
 
    pub expr_info: Vec<MonomorphExpressionInfo>
 
}
 

	
 
pub struct MonomorphExpressionInfo {
 
    pub type_id: TypeId,
 
    pub index: i32, // for called procedure's monomorphs, or selected field indices
 
}
 

	
 
/// Generic storage for functions, primitive components and composite
 
/// components.
 
// Note that we will have function definitions for builtin functions as well. In
 
@@ -1035,7 +1048,7 @@ pub struct ProcedureDefinition {
 
    pub scope: ScopeId,
 
    pub body: BlockStatementId,
 
    // Monomorphization of typed procedures
 

	
 
    pub monomorphs: Vec<ProcedureMonomorph>,
 
    // Validation/linking
 
    pub num_expressions_in_body: i32,
 
}
 
@@ -1054,6 +1067,7 @@ impl ProcedureDefinition {
 
            parameters: Vec::new(),
 
            scope: ScopeId::new_invalid(),
 
            body: BlockStatementId::new_invalid(),
 
            monomorphs: Vec::new(),
 
            num_expressions_in_body: -1,
 
        }
 
    }
 
@@ -1568,7 +1582,8 @@ pub struct AssignmentExpression {
 
    pub right: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1581,7 +1596,8 @@ pub struct BindingExpression {
 
    pub bound_from: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1595,7 +1611,8 @@ pub struct ConditionalExpression {
 
    pub false_expression: ExpressionId,
 
    // Validator/Linking
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 
@@ -1632,7 +1649,8 @@ pub struct BinaryExpression {
 
    pub right: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 
@@ -1653,7 +1671,8 @@ pub struct UnaryExpression {
 
    pub expression: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1666,7 +1685,8 @@ pub struct IndexingExpression {
 
    pub index: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1680,7 +1700,8 @@ pub struct SlicingExpression {
 
    pub to_index: ExpressionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1699,7 +1720,8 @@ pub struct SelectExpression {
 
    pub kind: SelectKind,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1712,7 +1734,8 @@ pub struct CastExpression {
 
    pub subject: ExpressionId,
 
    // Validator/linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1727,7 +1750,8 @@ pub struct CallExpression {
 
    pub procedure: ProcedureDefinitionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone, PartialEq, Eq)]
 
@@ -1763,7 +1787,8 @@ pub struct LiteralExpression {
 
    pub value: Literal,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
    // Typing
 
    pub expr_index: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
@@ -1860,5 +1885,6 @@ pub struct VariableExpression {
 
    pub declaration: Option<VariableId>,
 
    pub used_as_binding_target: bool,
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32, // used to index into type table after all types are determined
 
    // Typing
 
    pub expr_index: i32,
 
}
 
\ No newline at end of file
src/protocol/parser/pass_typing.rs
Show inline comments
 
@@ -1989,8 +1989,11 @@ impl PassTyping {
 
            Ok(concrete_type)
 
        }
 

	
 
        // Inference is now done. But we may still have uninferred types. So we
 
        // check for these.
 
        // Inference is now done. But we may still have polymorphic data that is
 
        // not fully inferred, while the associated expression is. An example
 
        // being a polymorphic function call: we need to instantiate a
 
        // monomorph, so need all of its polymorphic variables, but the call
 
        // expression was only interested in the return value.
 
        for infer_expr in self.infer_nodes.iter_mut() {
 
            if !infer_expr.expr_type.is_done {
 
                let expr = &ctx.heap[infer_expr.expr_id];
 
@@ -2004,9 +2007,6 @@ impl PassTyping {
 

	
 
            // Expression is fine, check if any extra data is attached
 
            if infer_expr.poly_data_index < 0 { continue; }
 

	
 
            // Extra data is attached, perform typechecking and transfer
 
            // resolved information to the expression
 
            let poly_data = &self.poly_data[infer_expr.poly_data_index as usize];
 

	
 
            // Note that only call and literal expressions need full inference.
 
@@ -2058,7 +2058,7 @@ impl PassTyping {
 
                    let concrete_type = inference_type_to_concrete_type(
 
                        ctx, infer_expr.expr_id, &poly_data.poly_vars, first_concrete_part
 
                    )?;
 
                    let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, definition_id, concrete_type)?;
 
                    let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, concrete_type)?;
 
                    infer_expr.type_id = type_id;
 
                },
 
                Expression::Select(_) => {
 
@@ -2071,20 +2071,25 @@ impl PassTyping {
 
        }
 

	
 
        // Every expression checked, and new monomorphs are queued. Transfer the
 
        // expression information to the type table.
 
        let procedure_arguments = &ctx.heap[self.procedure_id].parameters;
 

	
 
        let target = ctx.types.get_procedure_monomorph_mut(self.reserved_type_id);
 
        debug_assert!(target.arg_types.is_empty()); // makes sure we never queue a procedure's type inferencing twice
 
        debug_assert!(target.expr_data.is_empty());
 
        // expression information to the AST. If this is the first time we're
 
        // visiting this procedure then we assign expression indices as well.
 
        let procedure = &mut ctx.heap[self.procedure_id];
 
        let mut monomorph = ProcedureDefinitionMonomorph{
 
            argument_types: Vec::with_capacity(procedure.parameters.len()),
 
            expr_info: Vec::with_capacity(self.infer_nodes().len()), // TODO: Initial reservation
 
        };
 

	
 
        // - Write the arguments to the procedure
 
        target.arg_types.reserve(procedure_arguments.len());
 
        for argument_id in procedure_arguments {
 
        // - Write the arguments
 
        for parameter_id in procedure.parameters.iter().copied() {
 
            let mut concrete = ConcreteType::default();
 
            let var_data = self.var_data.iter().find(|v| v.var_id == *argument_id).unwrap();
 
            let var_data = self.var_data.iter().find(|v| v.var_id == parameter_id).unwrap();
 
            var_data.var_type.write_concrete_type(&mut concrete);
 
            target.arg_types.push(concrete);
 
            let type_id = ctx.types.add_monomorphed_type(ctx.modules, ctx.heap, ctx.arch, concrete)?;
 
            monomorph.argument_types.push(type_id)
 
        }
 

	
 
        for infer_node in self.infer_nodes.iter() {
 
            let expr = &ctx.heap[infer_node.expr_id];
 
        }
 

	
 
        // - Write the expression data
src/protocol/parser/type_table.rs
Show inline comments
 
@@ -699,20 +699,6 @@ impl TypeTable {
 
        return &self.mono_types[type_id.0 as usize];
 
    }
 

	
 
    /// Returns a mutable reference to a procedure's monomorph expression data.
 
    /// Used by typechecker to fill in previously reserved type information
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph_mut(&mut self, type_id: TypeId) -> &mut ProcedureMonomorph {
 
        let mono_type = &mut self.mono_types[type_id.0 as usize];
 
        return mono_type.variant.as_procedure_mut();
 
    }
 

	
 
    #[inline]
 
    pub(crate) fn get_procedure_monomorph(&self, type_id: TypeId) -> &ProcedureMonomorph {
 
        let mono_type = &self.mono_types[type_id.0 as usize];
 
        return mono_type.variant.as_procedure();
 
    }
 

	
 
    /// Reserves space for a monomorph of a polymorphic procedure. The index
 
    /// will point into a (reserved) slot of the array of expression types. The
 
    /// monomorph may NOT exist yet (because the reservation implies that we're
 
@@ -736,7 +722,6 @@ impl TypeTable {
 

	
 
    /// Adds a builtin type to the type table. As this is only called by the
 
    /// compiler during setup we assume it cannot fail.
 
    // TODO: Finish this train of thought, requires a little bit of design work
 
    pub(crate) fn add_builtin_type(&mut self, concrete_type: ConcreteType, poly_vars: &[PolymorphicVariable], size: usize, alignment: usize) -> TypeId {
 
        self.mono_search_key.set(&concrete_type.parts, poly_vars);
 
        debug_assert!(!self.mono_type_lookup.contains_key(&self.mono_search_key));
 
@@ -757,15 +742,20 @@ impl TypeTable {
 
    /// Adds a monomorphed type to the type table. If it already exists then the
 
    /// previous entry will be used.
 
    pub(crate) fn add_monomorphed_type(
 
        &mut self, modules: &[Module], heap: &Heap, arch: &TargetArch,
 
        definition_id: DefinitionId, concrete_type: ConcreteType
 
        &mut self, modules: &[Module], heap: &Heap, arch: &TargetArch, concrete_type: ConcreteType
 
    ) -> Result<TypeId, ParseError> {
 
        debug_assert_eq!(definition_id, get_concrete_type_definition(&concrete_type.parts).unwrap());
 
        let poly_vars = match get_concrete_type_definition(&concrete_type.parts) {
 
            Some(definition_id) => {
 
                let definition = self.definition_lookup.get(&definition_id).unwrap();
 
                definition.poly_vars.as_slice()
 
            },
 
            None => {
 
                &[]
 
            }
 
        };
 

	
 
        // Check if the concrete type was already added
 
        let definition = self.definition_lookup.get(&definition_id).unwrap();
 
        let poly_var_in_use = &definition.poly_vars;
 
        self.mono_search_key.set(&concrete_type.parts, poly_var_in_use.as_slice());
 
        self.mono_search_key.set(&concrete_type.parts, poly_vars);
 
        if let Some(type_id) = self.mono_type_lookup.get(&self.mono_search_key) {
 
            return Ok(*type_id);
 
        }
0 comments (0 inline, 0 general)