Changeset - b374c6bff853
[Not reviewed]
0 5 0
MH - 4 years ago 2021-12-14 22:09:53
contact@maxhenger.nl
Fix introduced bugs
5 files changed with 58 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/protocol/mod.rs
Show inline comments
 
@@ -119,25 +119,25 @@ impl ProtocolDescription {
 

	
 
        // - for each argument try to make sure the types match
 
        for arg_idx in 0..arguments.values.len() {
 
            let expected_type = &mono_type.arg_types[arg_idx];
 
            let provided_value = &arguments.values[arg_idx];
 
            if !self.verify_same_type(expected_type, 0, &arguments, provided_value) {
 
                return Err(ComponentCreationError::InvalidArgumentType(arg_idx));
 
            }
 
        }
 

	
 
        // By now we're sure that all of the arguments are correct. So create
 
        // the connector.
 
        return Ok(Prompt::new(&self.types, &self.heap, definition_id, 0, arguments));
 
        return Ok(Prompt::new(&self.types, &self.heap, definition_id, mono_index, arguments));
 
    }
 

	
 
    fn lookup_module_root(&self, module_name: &[u8]) -> Option<RootId> {
 
        for module in self.modules.iter() {
 
            match &module.name {
 
                Some(name) => if name.as_bytes() == module_name {
 
                    return Some(module.root_id);
 
                },
 
                None => if module_name.is_empty() {
 
                    return Some(module.root_id);
 
                }
 
            }
src/protocol/parser/pass_typing.rs
Show inline comments
 
@@ -828,25 +828,25 @@ pub(crate) struct ResolveQueueElement {
 
    pub(crate) root_id: RootId,
 
    pub(crate) definition_id: DefinitionId,
 
    pub(crate) reserved_monomorph_idx: i32,
 
}
 

	
 
pub(crate) type ResolveQueue = Vec<ResolveQueueElement>;
 

	
 
#[derive(Clone)]
 
struct InferenceExpression {
 
    expr_type: InferenceType,       // result type from expression
 
    expr_id: ExpressionId,          // expression that is evaluated
 
    field_or_monomorph_idx: i32,    // index of field, of index of monomorph array in type table
 
    extra_data_idx: i32,     // index of extra data needed for inference
 
    extra_data_idx: i32,            // index of extra data needed for inference
 
}
 

	
 
impl Default for InferenceExpression {
 
    fn default() -> Self {
 
        Self{
 
            expr_type: InferenceType::default(),
 
            expr_id: ExpressionId::new_invalid(),
 
            field_or_monomorph_idx: -1,
 
            extra_data_idx: -1,
 
        }
 
    }
 
}
 
@@ -1492,25 +1492,24 @@ impl PassTyping {
 
                            expr_type.display_name(&ctx.heap)
 
                        )
 
                    ));
 
                }
 
            }
 

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

	
 
            // Extra data is attached, perform typechecking and transfer
 
            // resolved information to the expression
 
            let extra_data = &self.extra_data[infer_expr.extra_data_idx as usize];
 
            if extra_data.poly_vars.is_empty() { continue; }
 

	
 
            // Note that only call and literal expressions need full inference.
 
            // Select expressions also use `extra_data`, but only for temporary
 
            // storage of the struct type whose field it is selecting.
 
            match &ctx.heap[extra_data.expr_id] {
 
                Expression::Call(expr) => {
 
                    // Check if it is not a builtin function. If not, then
 
                    // construct the first part of the concrete type.
 
                    let first_concrete_part = if expr.method == Method::UserFunction {
 
                        ConcreteTypePart::Function(expr.definition, extra_data.poly_vars.len() as u32)
 
                    } else if expr.method == Method::UserComponent {
 
                        ConcreteTypePart::Component(expr.definition, extra_data.poly_vars.len() as u32)
src/protocol/parser/type_table.rs
Show inline comments
 
@@ -421,25 +421,26 @@ impl Hash for MonomorphKey {
 
                if self.in_use[in_use_index] {
 
                    section.hash(state);
 
                }
 
                in_use_index += 1;
 
            }
 
        }
 
    }
 
}
 

	
 
impl PartialEq for MonomorphKey {
 
    fn eq(&self, other: &Self) -> bool {
 
        if self.in_use.is_empty() {
 
            return self.parts == other.parts;
 
            let temp_result = self.parts == other.parts;
 
            return temp_result;
 
        } else {
 
            // Outer type does not match
 
            if self.parts[0] != other.parts[0] {
 
                return false;
 
            }
 

	
 
            debug_assert_eq!(self.parts[0].num_embedded() as usize, self.in_use.len());
 
            let mut iter_self = ConcreteTypeIter::new(self.parts.as_slice(), 0);
 
            let mut iter_other = ConcreteTypeIter::new(other.parts.as_slice(), 0);
 
            let mut index = 0;
 
            while let Some(section_self) = iter_self.next() {
 
                let section_other = iter_other.next().unwrap();
 
@@ -482,50 +483,49 @@ pub(crate) struct MonomorphTable {
 
    // boilerplate. I opted for the `UnsafeCell` instead of the boilerplate.
 
    key: UnsafeCell<MonomorphKey>,
 
}
 

	
 
impl MonomorphTable {
 
    fn new() -> Self {
 
        return Self {
 
            lookup: HashMap::with_capacity(256),
 
            monomorphs: Vec::with_capacity(256),
 
            key: UnsafeCell::new(MonomorphKey{
 
                parts: Vec::with_capacity(32),
 
                in_use: Vec::with_capacity(32),
 
            })
 
            }),
 
        }
 
    }
 

	
 
    fn insert_with_zero_size_and_alignment(&mut self, concrete_type: ConcreteType, in_use: &[PolymorphicVariable], variant: MonomorphVariant) -> i32 {
 
        let key = MonomorphKey{
 
            parts: Vec::from(concrete_type.parts.as_slice()),
 
            in_use: in_use.iter().map(|v| v.is_in_use).collect(),
 
        };
 
        let index = self.monomorphs.len();
 
        let _result = self.lookup.insert(key, index as i32);
 
        debug_assert!(_result.is_none()); // did not exist yet
 
        self.monomorphs.push(TypeMonomorph{
 
            concrete_type,
 
            size: 0,
 
            alignment: 0,
 
            variant,
 
        });
 

	
 
        return index as i32;
 
    }
 

	
 
    fn get_monomorph_index(&self, parts: &[ConcreteTypePart], in_use: &[PolymorphicVariable]) -> Option<i32> {
 
        // Note: the entire goal of this internal `MonomorphKey` is to prevent
 
        // allocation. So:
 
        let key = unsafe {
 
            // Clear-and-extend to, at some point, prevent future allocations
 
            let key = &mut *self.key.get();
 
            key.parts.clear();
 
            key.parts.extend_from_slice(parts);
 
            key.in_use.clear();
 
            key.in_use.extend(in_use.iter().map(|v| v.is_in_use));
 

	
 
            &*key
 
        };
 

	
 
        match self.lookup.get(key) {
 
            Some(index) => return Some(*index),
 
            None => return None,
 
@@ -1034,27 +1034,33 @@ impl TypeTable {
 
                identifier: parameter.identifier.clone(),
 
                parser_type: parameter.parser_type.clone(),
 
            });
 
        }
 

	
 
        // Check conflict of identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &arguments, |arg| &arg.identifier, "connector argument"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of component
 
        // FIXME: Marking used polymorphic variables on procedures requires
 
        //  making sure that each is used in the body. For now, mark them all
 
        //  as required.
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
        for argument in &arguments {
 
            Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        // for argument in &arguments {
 
        //     Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        // }
 
        for poly_var in &mut poly_vars {
 
            poly_var.is_in_use = true;
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.type_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Component(ComponentType{ variant: definition.variant, arguments }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
@@ -1755,25 +1761,25 @@ impl TypeTable {
 
                        MemoryLayoutResult::PushBreadcrumb(new_breadcrumb) => {
 
                            self.memory_layout_breadcrumbs[cur_breadcrumb_idx] = breadcrumb;
 
                            self.memory_layout_breadcrumbs.push(new_breadcrumb);
 
                            continue 'breadcrumb_loop;
 
                        },
 
                    }
 

	
 
                    breadcrumb.next_member += 1;
 
                }
 

	
 
                // If here then we can compute the memory layout of the tuple.
 
                let mut cur_offset = 0;
 
                let mut max_alignment = 0;
 
                let mut max_alignment = 1;
 

	
 
                let mono_info = self.mono_lookup.get_mut(breadcrumb.monomorph_idx);
 
                let mono_tuple = mono_info.variant.as_tuple_mut();
 
                let mut size_alignment_index = breadcrumb.first_size_alignment_idx;
 
                for member_index in 0..num_members {
 
                    let (member_size, member_alignment) = self.size_alignment_stack[size_alignment_index];
 
                    align_offset_to(&mut cur_offset, member_alignment);
 
                    size_alignment_index += 1;
 

	
 
                    let member = &mut mono_tuple.members[member_index];
 
                    member.size = member_size;
 
                    member.alignment = member_alignment;
src/protocol/tests/parser_validation.rs
Show inline comments
 
@@ -413,32 +413,63 @@ fn test_correct_tuple_polymorph_args() {
 
        "single tuple arg",
 
        "
 
        union Option<T>{ Some(T), None }
 
        func thing() -> u32 {
 
            auto a = Option<()>::None;
 
            auto b = Option<(u32, u64)>::None;
 
            auto c = Option<(Option<(u8, s8)>, Option<(s8, u8)>)>::None;
 
            return 0;
 
        }
 
        "
 
    ).for_union("Option", |u| { u
 
        .assert_has_monomorph("Option<()>")
 
        .assert_has_monomorph("Option<(u32, u64)>")
 
        .assert_has_monomorph("Option<(Option<(u8,s8)>,Option<(s8,u8)>)>");
 
        .assert_has_monomorph("Option<(u32,u64)>")
 
        .assert_has_monomorph("Option<(Option<(u8,s8)>,Option<(s8,u8)>)>")
 
        .assert_size_alignment("Option<()>", 1, 1, 0, 0)
 
        .assert_size_alignment("Option<(u32,u64)>", 24, 8, 0, 0) // (u32, u64) becomes size 16, alignment 8. Hence union tag is aligned to 8
 
        .assert_size_alignment("Option<(Option<(u8,s8)>,Option<(s8,u8)>)>", 7, 1, 0, 0); // inner unions are size 3, alignment 1. Two of those with a tag is size 7
 
    });
 
}
 

	
 
#[test]
 
fn test_incorrect_tuple_polymorph_args() {
 
    todo!("write");
 
    // Do some mismatching brackets. I don't know what else to test
 
    Tester::new_single_source_expect_err(
 
        "mismatch angle bracket",
 
        "
 
        union Option<T>{ Some(T), None }
 
        func f() -> u32 {
 
            auto a = Option<(u32>)::None;
 
            return 0;
 
        }"
 
    ).error(|e| { e
 
        .assert_num(2)
 
        .assert_msg_has(0, "closing '>'").assert_occurs_at(0, ">)::None")
 
        .assert_msg_has(1, "match this '('").assert_occurs_at(1, "(u32>");
 
    });
 

	
 
    Tester::new_single_source_expect_err(
 
        "wrongly placed angle",
 
        "
 
        union O<T>{ S(T), N }
 
        func f() -> u32 {
 
            auto a = O<(<u32>)>::None;
 
            return 0;
 
        }
 
        "
 
    ).error(|e| { e
 
        .assert_num(1)
 
        .assert_msg_has(0, "expected typename")
 
        .assert_occurs_at(0, "<u32");
 
    });
 
}
 

	
 
#[test]
 
fn test_polymorph_array_types() {
 
    Tester::new_single_source_expect_ok(
 
        "array of polymorph in struct",
 
        "
 
        struct Foo<T> { T[] hello }
 
        struct Bar { Foo<u32>[] world }
 
        "
 
    ).for_struct("Bar", |s| { s
 
        .for_field("world", |f| { f.assert_parser_type("Foo<u32>[]"); });
src/protocol/tests/utils.rs
Show inline comments
 
@@ -964,25 +964,33 @@ fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph
 

	
 
        let first_idx = full_buffer.len();
 
        full_buffer.push_str(concrete_type.display_name(ctx.heap).as_str());
 
        if &full_buffer[first_idx..] == serialized_monomorph {
 
            has_match = Some(mono_idx as i32);
 
        }
 

	
 
        full_buffer.push('"');
 
    };
 

	
 
    // Bit wasteful, but this is (temporary?) testing code:
 
    for (mono_idx, mono) in ctx.types.mono_lookup.monomorphs.iter().enumerate() {
 
        append_to_full_buffer(&mono.concrete_type, mono_idx);
 
        let got_definition_id = match &mono.concrete_type.parts[0] {
 
            ConcreteTypePart::Instance(v, _) |
 
            ConcreteTypePart::Function(v, _) |
 
            ConcreteTypePart::Component(v, _) => *v,
 
            _ => DefinitionId::new_invalid(),
 
        };
 
        if got_definition_id == definition_id {
 
            append_to_full_buffer(&mono.concrete_type, mono_idx);
 
        }
 
    }
 

	
 
    full_buffer.push(']');
 

	
 
    (has_match, full_buffer)
 
}
 

	
 
fn serialize_parser_type(buffer: &mut String, heap: &Heap, parser_type: &ParserType) {
 
    use ParserTypeVariant as PTV;
 

	
 
    fn serialize_variant(buffer: &mut String, heap: &Heap, parser_type: &ParserType, mut idx: usize) -> usize {
 
        match &parser_type.elements[idx].variant {
0 comments (0 inline, 0 general)