Skip to content

Commit

Permalink
Add .! for mutable field offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Aug 11, 2024
1 parent 0d704f2 commit 91f0d34
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 86 deletions.
2 changes: 1 addition & 1 deletion examples/codegen/pass_by_ref.an
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ foo (x: S) (y: S) =
printne "x before: "
print x
z = mut y
z.&message := "modifying y"
z.!message := "modifying y"
printne "x after: "
print x

Expand Down
50 changes: 25 additions & 25 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl Display for DiagnosticKind {
DiagnosticKind::PreviouslyDefinedHere(item) => {
write!(f, "{} was previously defined here", item)
},
DiagnosticKind::IncorrectConstructorArgCount(item, expected, actual) => {
DiagnosticKind::IncorrectConstructorArgCount(item, actual, expected) => {
let plural_s = if *expected == 1 { "" } else { "s" };
let is_are = if *actual == 1 { "is" } else { "are" };
write!(
Expand All @@ -161,7 +161,7 @@ impl Display for DiagnosticKind {
item, expected, plural_s, actual, is_are
)
},
DiagnosticKind::IncorrectImplTraitArgCount(trait_name, expected, actual) => {
DiagnosticKind::IncorrectImplTraitArgCount(trait_name, actual, expected) => {
let plural_s = if *expected == 1 { "" } else { "s" };
write!(f, "impl has {} type argument{} but {} requires {}", expected, plural_s, trait_name, actual)
},
Expand Down Expand Up @@ -240,78 +240,78 @@ impl Display for DiagnosticKind {
"Invalid syntax in irrefutable pattern, expected a name, type annotation, or type constructor"
)
},
DiagnosticKind::FunctionParameterCountMismatch(typ, expected, actual) => {
DiagnosticKind::FunctionParameterCountMismatch(typ, actual, expected) => {
let plural_s = if *expected == 1 { "" } else { "s" };
let was_were = if *actual == 1 { "was" } else { "were" };
write!(f, "Function of type {typ} declared to take {expected} parameter{plural_s}, but {actual} {was_were} supplied")
},
DiagnosticKind::TypeError(TypeErrorKind::ExpectedUnitTypeFromPattern, _expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::ExpectedUnitTypeFromPattern, actual, _expected) => {
write!(f, "Expected a unit type from this pattern, but the corresponding value has the type {}", actual)
},
DiagnosticKind::TypeError(TypeErrorKind::ExpectedPairTypeFromPattern, _, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::ExpectedPairTypeFromPattern, actual, _expected) => {
write!(f, "Expected a pair type from this pattern, but found {actual}")
},
DiagnosticKind::TypeError(TypeErrorKind::VariableDoesNotMatchDeclaredType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::VariableDoesNotMatchDeclaredType, actual, expected) => {
write!(f, "Variable type {actual} does not match its declared type of {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::PatternTypeDoesNotMatchAnnotatedType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::PatternTypeDoesNotMatchAnnotatedType, actual, expected) => {
write!(f, "Pattern type {actual} does not match the annotated type {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::PatternTypeDoesNotMatchDefinitionType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::PatternTypeDoesNotMatchDefinitionType, actual, expected) => {
write!(f, "Pattern type {actual} does not match the definition's type {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::FunctionBodyDoesNotMatchReturnType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::FunctionBodyDoesNotMatchReturnType, actual, expected) => {
write!(f, "Function body type {actual} does not match declared return type of {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::CalledValueIsNotAFunction, _, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::CalledValueIsNotAFunction, actual, _expected) => {
write!(f, "Value being called is not a function, it is a {actual}")
},
DiagnosticKind::TypeError(TypeErrorKind::ArgumentTypeMismatch, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::ArgumentTypeMismatch, actual, expected) => {
write!(f, "Expected argument of type {expected}, but found {actual}")
},
DiagnosticKind::TypeError(TypeErrorKind::NonBoolInCondition, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::NonBoolInCondition, actual, expected) => {
write!(f, "{actual} should be a {expected} to be used in an if condition")
},
DiagnosticKind::TypeError(TypeErrorKind::IfBranchMismatch, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::IfBranchMismatch, actual, expected) => {
write!(
f,
"Expected 'then' and 'else' branch types to match, but found {expected} and {actual} respectively"
)
},
DiagnosticKind::TypeError(TypeErrorKind::MatchPatternTypeDiffers, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::MatchPatternTypeDiffers, actual, expected) => {
write!(f, "This pattern of type {actual} does not match the type {expected} that is being matched on")
},
DiagnosticKind::TypeError(TypeErrorKind::MatchReturnTypeDiffers, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::MatchReturnTypeDiffers, actual, expected) => {
write!(
f,
"This branch's return type {actual} does not match the previous branches which return {expected}"
)
},
DiagnosticKind::TypeError(TypeErrorKind::DoesNotMatchAnnotatedType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::DoesNotMatchAnnotatedType, actual, expected) => {
write!(f, "Expression of type {actual} does not match its annotated type {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::ExpectedStructReference, _, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::ExpectedStructReference, actual, _expected) => {
write!(f, "Expected a struct reference but found {actual} instead")
},
DiagnosticKind::TypeError(TypeErrorKind::NoFieldOfType(field_name), expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::NoFieldOfType(field_name), actual, expected) => {
write!(f, "{actual} has no field '{field_name}' of type {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::AssignToNonMutRef, expected, actual) => {
write!(f, "Expression of type {actual} must be a `{expected}` to be assigned to")
DiagnosticKind::TypeError(TypeErrorKind::AssignToNonMutRef, actual, expected) => {
write!(f, "Expression of type {actual} must be a mutable reference type ({expected}) to be assigned to")
},
DiagnosticKind::TypeError(TypeErrorKind::AssignToWrongType, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::AssignToWrongType, actual, expected) => {
write!(f, "Cannot assign expression of type {actual} to a Ref of type {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::HandleBranchMismatch, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::HandleBranchMismatch, actual, expected) => {
write!(f, "The type of this branch ({actual}) should match the type of the expression being handled: {expected}")
},
DiagnosticKind::TypeError(TypeErrorKind::PatternReturnTypeMismatch, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::PatternReturnTypeMismatch, actual, expected) => {
write!(f, "Expected type {expected} does not match the pattern's return type {actual}")
},
DiagnosticKind::TypeError(TypeErrorKind::NeverShown, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::NeverShown, actual, expected) => {
unreachable!("This type error should never be shown. Expected {}, Actual {}", expected, actual)
},
DiagnosticKind::TypeError(TypeErrorKind::MonomorphizationError, expected, actual) => {
DiagnosticKind::TypeError(TypeErrorKind::MonomorphizationError, actual, expected) => {
unreachable!(
"Unification error during monomorphisation: Could not unify definition {} with instantiation {}",
expected, actual
Expand Down
8 changes: 4 additions & 4 deletions src/hir/monomorphisation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1572,17 +1572,17 @@ impl<'c> Context<'c> {
let result_type = self.convert_type(member_access.typ.as_ref().unwrap());

// If our collection type is a ref we do a ptr offset instead of a direct access
match (ref_type, member_access.is_offset) {
(Some(elem_type), true) => {
match (ref_type, member_access.offset) {
(Some(elem_type), Some(_)) => {
let offset = Self::get_field_offset(&elem_type, index);
offset_ptr(lhs, offset as u64)
},
(Some(elem_type), false) => {
(Some(elem_type), None) => {
let lhs = hir::Ast::Builtin(hir::Builtin::Deref(Box::new(lhs), elem_type));
Self::extract(lhs, index, result_type)
},
_ => {
assert!(!member_access.is_offset);
assert!(member_access.offset.is_none());
Self::extract(lhs, index, result_type)
},
}
Expand Down
3 changes: 2 additions & 1 deletion src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,8 @@ impl<'cache, 'contents> Iterator for Lexer<'cache, 'contents> {
self.previous_token_expects_indent = true;
self.advance2_with(Token::RightArrow)
},
('.', '&') => self.advance2_with(Token::MemberReference),
('.', '&') => self.advance2_with(Token::MemberRef),
('.', '!') => self.advance2_with(Token::MemberMutRef),
('.', _) => self.advance_with(Token::MemberAccess),
('-', _) => self.lex_negative(),
('!', '=') => self.advance2_with(Token::NotEqual),
Expand Down
6 changes: 4 additions & 2 deletions src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ pub enum Token {
Semicolon, // ;
Comma, // ,
MemberAccess, // .
MemberReference, // .&
MemberRef, // .&
MemberMutRef, // .!
LessThan, // <
GreaterThan, // >
LessThanOrEqual, // <=
Expand Down Expand Up @@ -327,7 +328,8 @@ impl Display for Token {
Token::Semicolon => write!(f, "';'"),
Token::Comma => write!(f, "','"),
Token::MemberAccess => write!(f, "'.'"),
Token::MemberReference => write!(f, "'.&'"),
Token::MemberRef => write!(f, "'.&'"),
Token::MemberMutRef => write!(f, "'.!'"),
Token::LessThan => write!(f, "'<'"),
Token::GreaterThan => write!(f, "'>'"),
Token::LessThanOrEqual => write!(f, "'<='"),
Expand Down
4 changes: 2 additions & 2 deletions src/nameresolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ impl<'c> NameResolver {
let expected = self.get_expected_type_argument_count(constructor, cache);
if args.len() != expected && !matches!(constructor, Type::TypeVariable(_)) {
let typename = constructor.display(cache).to_string();
cache.push_diagnostic(location, D::IncorrectConstructorArgCount(typename, expected, args.len()));
cache.push_diagnostic(location, D::IncorrectConstructorArgCount(typename, args.len(), expected));
}

// Check argument is an integer/float type (issue #146)
Expand Down Expand Up @@ -1413,7 +1413,7 @@ impl<'c> Resolvable<'c> for ast::TraitImpl<'c> {
let required_arg_count = trait_info.typeargs.len() + trait_info.fundeps.len();
if self.trait_args.len() != required_arg_count {
let trait_name = self.trait_name.clone();
let error = D::IncorrectImplTraitArgCount(trait_name, self.trait_args.len(), required_arg_count);
let error = D::IncorrectImplTraitArgCount(trait_name, required_arg_count, self.trait_args.len());
cache.push_diagnostic(self.location, error);
}

Expand Down
10 changes: 6 additions & 4 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,10 @@ pub struct MemberAccess<'a> {
pub lhs: Box<Ast<'a>>,
pub field: String,
pub location: Location<'a>,
/// True if this is an offset .& operation
pub is_offset: bool,

/// If this member access is an offset rather
/// than a move/copy, this will contain the mutability of the offset.
pub offset: Option<Mutability>,
pub typ: Option<types::Type>,
}

Expand Down Expand Up @@ -716,8 +718,8 @@ impl<'a> Ast<'a> {
Ast::Extern(Extern { declarations, location, level: None, typ: None })
}

pub fn member_access(lhs: Ast<'a>, field: String, is_offset: bool, location: Location<'a>) -> Ast<'a> {
Ast::MemberAccess(MemberAccess { lhs: Box::new(lhs), field, is_offset, location, typ: None })
pub fn member_access(lhs: Ast<'a>, field: String, offset: Option<Mutability>, location: Location<'a>) -> Ast<'a> {
Ast::MemberAccess(MemberAccess { lhs: Box::new(lhs), field, offset, location, typ: None })
}

pub fn assignment(lhs: Ast<'a>, rhs: Ast<'a>, location: Location<'a>) -> Ast<'a> {
Expand Down
8 changes: 6 additions & 2 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,12 @@ fn pattern_function_argument<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b>
fn member_access<'a, 'b>(input: Input<'a, 'b>) -> AstResult<'a, 'b> {
let (mut input, mut arg, mut location) = argument(input)?;

while input[0].0 == Token::MemberAccess || input[0].0 == Token::MemberReference {
let is_reference = input[0].0 == Token::MemberReference;
while input[0].0 == Token::MemberAccess || input[0].0 == Token::MemberRef || input[0].0 == Token::MemberMutRef {
let is_reference = match input[0].0 {
Token::MemberMutRef => Some(Mutability::Mutable),
Token::MemberRef => Some(Mutability::Immutable),
_ => None,
};
input = &input[1..];

let (new_input, field, field_location) = no_backtracking(identifier)(input)?;
Expand Down
Loading

0 comments on commit 91f0d34

Please sign in to comment.