Skip to content

Commit

Permalink
Fix type-checking with mutable type parameters
Browse files Browse the repository at this point in the history
When checking types that are mutable with a mutable type parameter, we
end up comparing against a placeholder with the parameter as a
requirement. This commit ensures we allow such a comparison, allowing
certain patterns such as taking a `mut Array[T: Compare[T]]` as an
argument and passing it e.g. `mut Array[Int]`.

This fixes #579.

Changelog: fixed
  • Loading branch information
yorickpeterse committed Jul 20, 2023
1 parent c756741 commit bc1273c
Showing 1 changed file with 38 additions and 0 deletions.
38 changes: 38 additions & 0 deletions types/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ impl Rules {
self.relaxed_ownership = false;
self
}

fn with_one_time_subtyping(mut self) -> Rules {
self.subtyping = TraitSubtyping::Once;
self
}
}

/// The type-checking environment.
Expand Down Expand Up @@ -756,6 +761,9 @@ impl<'a> TypeChecker<'a> {
return true;
}

// At this point no value is assigned yet, so it's safe to allow
// sub-typing through traits.
let rules = rules.with_one_time_subtyping();
let res = match left_id {
TypeId::ClassInstance(lhs) => reqs
.into_iter()
Expand Down Expand Up @@ -1611,6 +1619,36 @@ mod tests {
assert_eq!(var.value(&db), Some(owned(rigid(param))));
}

#[test]
fn test_mut_with_mut_placeholder_with_requirements() {
let mut db = Database::new();
let param = new_parameter(&mut db, "T");
let to_foo = new_trait(&mut db, "ToFoo");
let array = ClassId::array();
let var = TypePlaceholder::alloc(&mut db, Some(param));

array.new_type_parameter(&mut db, "T".to_string());
param.add_requirements(&mut db, vec![trait_instance(to_foo)]);
ClassId::int().add_trait_implementation(
&mut db,
TraitImplementation {
instance: trait_instance(to_foo),
bounds: TypeBounds::new(),
},
);

let given =
mutable(generic_instance_id(&mut db, array, vec![TypeRef::int()]));

let exp = mutable(generic_instance_id(
&mut db,
array,
vec![placeholder(var)],
));

check_ok(&db, given, exp);
}

#[test]
fn test_ref_uni() {
let mut db = Database::new();
Expand Down

0 comments on commit bc1273c

Please sign in to comment.