Skip to content

Commit

Permalink
WIP: Introduce "move" bound for type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
yorickpeterse committed Nov 16, 2023
1 parent 8d3c6ef commit 5e55906
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 71 deletions.
2 changes: 2 additions & 0 deletions ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,13 +584,15 @@ impl Node for ReopenClass {
pub enum Requirement {
Trait(TypeName),
Mutable(SourceLocation),
Movable(SourceLocation),
}

impl Node for Requirement {
fn location(&self) -> &SourceLocation {
match self {
Requirement::Trait(n) => &n.location,
Requirement::Mutable(loc) => loc,
Requirement::Movable(loc) => loc,
}
}
}
Expand Down
16 changes: 9 additions & 7 deletions ast/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,7 @@ impl Parser {
let token = self.require()?;
let req = match token.kind {
TokenKind::Mut => Requirement::Mutable(token.location),
TokenKind::Move => Requirement::Movable(token.location),
_ => Requirement::Trait(
self.type_name_with_optional_namespace(token)?,
),
Expand Down Expand Up @@ -5133,7 +5134,7 @@ mod tests {
);

assert_eq!(
top(parse("impl A for B if X: A + B, Y: C + mut {}")),
top(parse("impl A for B if X: A + B, Y: C + mut + move {}")),
TopLevelExpression::ImplementTrait(Box::new(ImplementTrait {
trait_name: TypeName {
name: Constant {
Expand All @@ -5151,7 +5152,7 @@ mod tests {
},
body: ImplementationExpressions {
values: Vec::new(),
location: cols(38, 39)
location: cols(45, 46)
},
bounds: Some(TypeBounds {
values: vec![
Expand Down Expand Up @@ -5203,16 +5204,17 @@ mod tests {
arguments: None,
location: cols(30, 30)
}),
Requirement::Mutable(cols(34, 36))
Requirement::Mutable(cols(34, 36)),
Requirement::Movable(cols(40, 43)),
],
location: cols(30, 36)
location: cols(30, 43)
},
location: cols(27, 36)
location: cols(27, 43)
}
],
location: cols(17, 36)
location: cols(17, 43)
}),
location: cols(1, 39)
location: cols(1, 46)
}))
);

Expand Down
5 changes: 2 additions & 3 deletions compiler/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,15 +797,14 @@ impl Diagnostics {
);
}

pub(crate) fn type_parameter_already_mutable(
pub(crate) fn conflicting_type_parameter_requirements(
&mut self,
name: &str,
file: PathBuf,
location: SourceLocation,
) {
self.error(
DiagnosticId::InvalidType,
format!("the type parameter '{}' is already mutable", name),
"type parameters can't require values to be both 'mut' and 'move'",
file,
location,
);
Expand Down
148 changes: 133 additions & 15 deletions compiler/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ pub(crate) struct TypeBound {
pub(crate) name: Constant,
pub(crate) requirements: Vec<TypeName>,
pub(crate) mutable: bool,
pub(crate) movable: bool,
pub(crate) location: SourceLocation,
}

Expand Down Expand Up @@ -577,6 +578,7 @@ pub(crate) struct TypeParameter {
pub(crate) name: Constant,
pub(crate) requirements: Vec<TypeName>,
pub(crate) mutable: bool,
pub(crate) movable: bool,
pub(crate) location: SourceLocation,
}

Expand Down Expand Up @@ -1361,27 +1363,37 @@ impl<'a> LowerToHir<'a> {
fn type_bound(&mut self, node: ast::TypeBound) -> TypeBound {
let name = self.constant(node.name);
let mut mutable = false;
let mut movable = false;
let mut requirements = Vec::new();

for req in node.requirements.values {
match req {
ast::Requirement::Trait(n) => {
requirements.push(self.type_name(n))
}
ast::Requirement::Mutable(loc) if mutable => {
self.state.diagnostics.type_parameter_already_mutable(
&name.name,
self.file(),
loc,
);
}
ast::Requirement::Mutable(_) => {
mutable = true;
}
ast::Requirement::Movable(_) => {
movable = true;
}
}
}

TypeBound { name, requirements, mutable, location: node.location }
if movable && mutable {
self.state.diagnostics.conflicting_type_parameter_requirements(
self.file(),
node.location.clone(),
);
}

TypeBound {
name,
requirements,
mutable,
movable,
location: node.location,
}
}

fn define_trait(&mut self, node: ast::DefineTrait) -> TopLevelExpression {
Expand Down Expand Up @@ -1648,6 +1660,7 @@ impl<'a> LowerToHir<'a> {
let name = self.constant(node.name);
let location = node.location;
let mut mutable = false;
let mut movable = false;
let mut requirements = Vec::new();

if let Some(reqs) = node.requirements {
Expand All @@ -1656,26 +1669,30 @@ impl<'a> LowerToHir<'a> {
ast::Requirement::Trait(n) => {
requirements.push(self.type_name(n))
}
ast::Requirement::Mutable(loc) if mutable => {
self.state.diagnostics.type_parameter_already_mutable(
&name.name,
self.file(),
loc,
);
}
ast::Requirement::Mutable(_) => {
mutable = true;
}
ast::Requirement::Movable(_) => {
movable = true;
}
}
}
}

if movable && mutable {
self.state.diagnostics.conflicting_type_parameter_requirements(
self.file(),
location.clone(),
);
}

TypeParameter {
type_parameter_id: None,
name,
requirements,
location,
mutable,
movable,
}
}

Expand Down Expand Up @@ -3393,6 +3410,7 @@ mod tests {
location: cols(11, 11)
}],
mutable: false,
movable: false,
location: cols(8, 11)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -3509,6 +3527,7 @@ mod tests {
location: cols(12, 12)
}],
mutable: false,
movable: false,
location: cols(9, 12)
}],
body: vec![ClassExpression::Field(Box::new(DefineField {
Expand All @@ -3535,6 +3554,67 @@ mod tests {
);
}

#[test]
fn test_lower_class_with_mutable_parameter() {
let hir = lower_top_expr("class A[B: mut] {}").0;

assert_eq!(
hir,
TopLevelExpression::Class(Box::new(DefineClass {
public: false,
kind: ClassKind::Regular,
class_id: None,
name: Constant { name: "A".to_string(), location: cols(7, 7) },
type_parameters: vec![TypeParameter {
type_parameter_id: None,
name: Constant {
name: "B".to_string(),
location: cols(9, 9)
},
requirements: Vec::new(),
mutable: true,
movable: false,
location: cols(9, 14)
}],
body: Vec::new(),
location: cols(1, 18)
})),
);
}

#[test]
fn test_lower_class_with_movable_parameter() {
let hir = lower_top_expr("class A[B: move] {}").0;

assert_eq!(
hir,
TopLevelExpression::Class(Box::new(DefineClass {
public: false,
kind: ClassKind::Regular,
class_id: None,
name: Constant { name: "A".to_string(), location: cols(7, 7) },
type_parameters: vec![TypeParameter {
type_parameter_id: None,
name: Constant {
name: "B".to_string(),
location: cols(9, 9)
},
requirements: Vec::new(),
mutable: false,
movable: true,
location: cols(9, 15)
}],
body: Vec::new(),
location: cols(1, 19)
})),
);
}

#[test]
fn test_lower_class_with_invalid_parameter_requirements() {
assert_eq!(lower_top_expr("class A[B: move + mut] {}").1, 1);
}

#[test]
fn test_lower_extern_class() {
let hir = lower_top_expr("class extern A { let @a: B }").0;
Expand Down Expand Up @@ -3660,6 +3740,7 @@ mod tests {
location: cols(20, 20)
}],
mutable: false,
movable: false,
location: cols(17, 20)
}],
body: vec![ClassExpression::Field(Box::new(DefineField {
Expand Down Expand Up @@ -3735,6 +3816,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(23, 23)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -3807,6 +3889,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(22, 22)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -3878,6 +3961,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(16, 16)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -3953,6 +4037,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(9, 9)
}],
requirements: vec![TypeName {
Expand Down Expand Up @@ -4020,6 +4105,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(16, 16)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -4151,6 +4237,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(16, 16)
}],
arguments: vec![MethodArgument {
Expand Down Expand Up @@ -4225,12 +4312,41 @@ mod tests {
},
requirements: Vec::new(),
mutable: true,
movable: false,
location: cols(11, 16),
}],
body: Vec::new(),
location: cols(1, 16)
}))
);

assert_eq!(
lower_top_expr("impl A if T: move {}").0,
TopLevelExpression::Reopen(Box::new(ReopenClass {
class_id: None,
class_name: Constant {
name: "A".to_string(),
location: cols(6, 6)
},
bounds: vec![TypeBound {
name: Constant {
name: "T".to_string(),
location: cols(11, 11)
},
requirements: Vec::new(),
mutable: false,
movable: true,
location: cols(11, 17),
}],
body: Vec::new(),
location: cols(1, 17)
}))
);
}

#[test]
fn test_lower_type_bound_with_invalid_requirements() {
assert_eq!(lower_top_expr("impl A if T: move + mut {}").1, 1);
}

#[test]
Expand Down Expand Up @@ -4474,6 +4590,7 @@ mod tests {
location: cols(20, 20)
},],
mutable: true,
movable: false,
location: cols(17, 26)
}],
body: Vec::new(),
Expand Down Expand Up @@ -6002,6 +6119,7 @@ mod tests {
},
requirements: Vec::new(),
mutable: false,
movable: false,
location: cols(19, 19)
}],
body: vec![
Expand Down
Loading

0 comments on commit 5e55906

Please sign in to comment.