Skip to content

Commit

Permalink
WIP: add support for the move type modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
yorickpeterse committed Nov 28, 2023
1 parent aa615ed commit a1e0442
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 111 deletions.
2 changes: 2 additions & 0 deletions ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ pub enum Type {
Ref(Box<ReferenceType>),
Mut(Box<ReferenceType>),
Uni(Box<ReferenceType>),
Owned(Box<ReferenceType>),
Closure(Box<ClosureType>),
Tuple(Box<TupleType>),
}
Expand All @@ -983,6 +984,7 @@ impl Node for Type {
Type::Ref(ref typ) => typ.location(),
Type::Mut(ref typ) => typ.location(),
Type::Uni(ref typ) => typ.location(),
Type::Owned(ref typ) => typ.location(),
Type::Closure(ref typ) => typ.location(),
Type::Tuple(ref typ) => typ.location(),
}
Expand Down
25 changes: 25 additions & 0 deletions ast/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ impl Parser {
TokenKind::Fn => Type::Closure(Box::new(self.closure_type(start)?)),
TokenKind::Ref => Type::Ref(Box::new(self.reference_type(start)?)),
TokenKind::Mut => Type::Mut(Box::new(self.reference_type(start)?)),
TokenKind::Move => {
Type::Owned(Box::new(self.reference_type(start)?))
}
TokenKind::Uni => Type::Uni(Box::new(self.reference_type(start)?)),
TokenKind::ParenOpen => {
Type::Tuple(Box::new(self.tuple_type(start)?))
Expand Down Expand Up @@ -3879,6 +3882,28 @@ mod tests {
);
}

#[test]
fn test_type_reference_with_owned_reference_type() {
let mut parser = parser("move A");
let start = parser.require().unwrap();

assert_eq!(
parser.type_reference(start).unwrap(),
Type::Owned(Box::new(ReferenceType {
type_reference: ReferrableType::Named(Box::new(TypeName {
name: Constant {
source: None,
name: "A".to_string(),
location: cols(6, 6),
},
arguments: None,
location: cols(6, 6)
})),
location: cols(1, 6)
}))
);
}

#[test]
fn test_type_reference_with_double_reference() {
let mut parser = parser("ref ref A");
Expand Down
25 changes: 25 additions & 0 deletions compiler/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ pub(crate) enum Type {
Ref(Box<ReferenceType>),
Mut(Box<ReferenceType>),
Uni(Box<ReferenceType>),
Owned(Box<ReferenceType>),
Closure(Box<ClosureType>),
Tuple(Box<TupleType>),
}
Expand All @@ -669,6 +670,7 @@ impl Type {
Type::Ref(ref node) => &node.location,
Type::Mut(ref node) => &node.location,
Type::Uni(ref node) => &node.location,
Type::Owned(ref node) => &node.location,
Type::Closure(ref node) => &node.location,
Type::Tuple(ref node) => &node.location,
}
Expand Down Expand Up @@ -1542,6 +1544,7 @@ impl<'a> LowerToHir<'a> {
}
ast::Type::Ref(node) => Type::Ref(self.reference_type(*node)),
ast::Type::Mut(node) => Type::Mut(self.reference_type(*node)),
ast::Type::Owned(node) => Type::Owned(self.reference_type(*node)),
ast::Type::Uni(node) => Type::Uni(self.reference_type(*node)),
ast::Type::Closure(node) => Type::Closure(self.closure_type(*node)),
ast::Type::Tuple(node) => Type::Tuple(self.tuple_type(*node)),
Expand Down Expand Up @@ -3330,6 +3333,28 @@ mod tests {
);
}

#[test]
fn test_lower_owned_reference_type() {
let hir = lower_type("move B");

assert_eq!(
hir,
Type::Owned(Box::new(ReferenceType {
type_reference: ReferrableType::Named(Box::new(TypeName {
source: None,
resolved_type: types::TypeRef::Unknown,
name: Constant {
name: "B".to_string(),
location: cols(14, 14)
},
arguments: Vec::new(),
location: cols(14, 14)
})),
location: cols(9, 14)
}))
);
}

#[test]
fn test_lower_closure_type() {
let hir = lower_type("fn (A) -> C");
Expand Down
18 changes: 6 additions & 12 deletions compiler/src/type_check/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ impl MethodCall {
};

// If the receiver is rigid, it may introduce additional type arguments
// through its type parameter requirements. These are typed as Infer(),
// through its type parameter requirements. These are typed as Any(),
// but we want them as rigid types. In addition, we need to take care or
// remapping any bound parameters.
//
Expand All @@ -363,7 +363,7 @@ impl MethodCall {
// handle it here when/if necessary.
if receiver.is_rigid_type_parameter(&state.db) {
for val in type_arguments.values_mut() {
if let TypeRef::Infer(TypeId::TypeParameter(id)) = val {
if let TypeRef::Any(TypeId::TypeParameter(id)) = val {
*val = TypeRef::Owned(TypeId::RigidTypeParameter(
bounds.get(*id).unwrap_or(*id),
));
Expand Down Expand Up @@ -3935,11 +3935,8 @@ impl<'a> CheckMethodBody<'a> {
scope: &mut LexicalScope,
) -> TypeRef {
let expr_type = self.expression(&mut node.value, scope);
let rules = Rules {
type_parameters_as_rigid: true,
type_parameters_as_owned: true,
..Default::default()
};
let rules =
Rules { type_parameters_as_rigid: true, ..Default::default() };

let type_scope = TypeScope::with_bounds(
self.module,
Expand Down Expand Up @@ -4272,11 +4269,8 @@ impl<'a> CheckMethodBody<'a> {
node: &mut hir::Type,
self_type: TypeId,
) -> TypeRef {
let rules = Rules {
type_parameters_as_rigid: true,
type_parameters_as_owned: true,
..Default::default()
};
let rules =
Rules { type_parameters_as_rigid: true, ..Default::default() };
let type_scope = TypeScope::with_bounds(
self.module,
self_type,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/type_check/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ impl<'a> DefineMethods<'a> {
let args = class_id
.type_parameters(self.db())
.into_iter()
.map(|param| TypeRef::Infer(TypeId::TypeParameter(param)))
.map(|param| TypeRef::Any(TypeId::TypeParameter(param)))
.collect();

ClassInstance::with_types(self.db_mut(), class_id, args)
Expand Down
56 changes: 27 additions & 29 deletions compiler/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub(crate) mod methods;

#[derive(Eq, PartialEq)]
enum RefKind {
Default,
Owned,
Ref,
Mut,
Expand All @@ -28,6 +29,12 @@ enum RefKind {
impl RefKind {
fn into_type_ref(self, id: TypeId) -> TypeRef {
match self {
Self::Default => match id {
TypeId::TypeParameter(_) | TypeId::RigidTypeParameter(_) => {
TypeRef::Any(id)
}
_ => TypeRef::Owned(id),
},
Self::Owned => TypeRef::Owned(id),
Self::Ref => TypeRef::Ref(id),
Self::Mut => TypeRef::Mut(id),
Expand Down Expand Up @@ -97,10 +104,6 @@ impl<'a> TypeScope<'a> {
/// Rules to apply when defining and checking the types of type signatures.
#[derive(Copy, Clone)]
pub(crate) struct Rules {
/// When set to `true`, type parameters are defined as owned values; rather
/// than allowing both owned values and references.
pub(crate) type_parameters_as_owned: bool,

/// When set to `true`, type parameters are defined as rigid parameters.
pub(crate) type_parameters_as_rigid: bool,

Expand All @@ -114,7 +117,6 @@ pub(crate) struct Rules {
impl Default for Rules {
fn default() -> Self {
Self {
type_parameters_as_owned: false,
type_parameters_as_rigid: false,
allow_private_types: true,
allow_refs: true,
Expand Down Expand Up @@ -169,7 +171,7 @@ impl<'a> DefineTypeSignature<'a> {
fn define_type(&mut self, node: &mut hir::Type) -> TypeRef {
match node {
hir::Type::Named(ref mut n) => {
self.define_type_name(n, RefKind::Owned)
self.define_type_name(n, RefKind::Default)
}
hir::Type::Ref(_) | hir::Type::Mut(_) if !self.rules.allow_refs => {
self.state.diagnostics.error(
Expand All @@ -189,6 +191,9 @@ impl<'a> DefineTypeSignature<'a> {
hir::Type::Uni(ref mut n) => {
self.define_reference_type(n, RefKind::Uni)
}
hir::Type::Owned(ref mut n) => {
self.define_reference_type(n, RefKind::Owned)
}
hir::Type::Closure(ref mut n) => {
self.define_closure_type(n, RefKind::Owned)
}
Expand Down Expand Up @@ -288,7 +293,7 @@ impl<'a> DefineTypeSignature<'a> {
// handling them first.
match name.as_str() {
"Never" => {
if kind == RefKind::Owned {
if kind == RefKind::Default {
TypeRef::Never
} else {
self.state.diagnostics.error(
Expand Down Expand Up @@ -403,30 +408,22 @@ impl<'a> DefineTypeSignature<'a> {
TypeId::TypeParameter(param_id)
};

match kind {
RefKind::Owned if self.rules.type_parameters_as_owned => {
TypeRef::Owned(type_id)
}
RefKind::Owned => TypeRef::Infer(type_id),
RefKind::Uni => TypeRef::Uni(type_id),
RefKind::Ref => TypeRef::Ref(type_id),
RefKind::Mut => {
if !param_id.is_mutable(self.db()) {
self.state.diagnostics.error(
DiagnosticId::InvalidType,
format!(
"the type 'mut {name}' is invalid, as '{name}' \
if let RefKind::Mut = kind {
if !param_id.is_mutable(self.db()) {
self.state.diagnostics.error(
DiagnosticId::InvalidType,
format!(
"the type 'mut {name}' is invalid, as '{name}' \
might be immutable at runtime",
name = id.name(self.db()),
),
self.file(),
node.location.clone(),
);
}

TypeRef::Mut(type_id)
name = id.name(self.db()),
),
self.file(),
node.location.clone(),
);
}
}

kind.into_type_ref(type_id)
}

fn define_closure_type(
Expand Down Expand Up @@ -623,6 +620,7 @@ impl<'a> CheckTypeSignature<'a> {
hir::Type::Ref(ref n) => self.check_reference_type(n),
hir::Type::Uni(ref n) => self.check_reference_type(n),
hir::Type::Mut(ref n) => self.check_reference_type(n),
hir::Type::Owned(ref n) => self.check_reference_type(n),
hir::Type::Closure(ref n) => self.check_closure_type(n),
hir::Type::Tuple(ref n) => self.check_tuple_type(n),
}
Expand Down Expand Up @@ -736,7 +734,7 @@ impl<'a> CheckTypeSignature<'a> {

for (param, node) in parameters.into_iter().zip(node.arguments.iter()) {
let arg = arguments.get(param).unwrap();
let exp = TypeRef::Infer(TypeId::TypeParameter(param));
let exp = TypeRef::Any(TypeId::TypeParameter(param));
let mut env = Environment::new(
arg.type_arguments(self.db()),
exp_args.clone(),
Expand Down
Loading

0 comments on commit a1e0442

Please sign in to comment.