diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index e94eb22d59..cc076385a8 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -3589,7 +3589,7 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { and( and( byte(b'?', ERecord::QuestionMark), - optional(byte(b'?', ERecord::QuestionMark)), + optional(byte(b'?', ERecord::SecondQuestionMark)), ), spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(true))), ), diff --git a/crates/compiler/parse/src/normalize.rs b/crates/compiler/parse/src/normalize.rs index 6ab1abad0e..857adb01ae 100644 --- a/crates/compiler/parse/src/normalize.rs +++ b/crates/compiler/parse/src/normalize.rs @@ -1219,6 +1219,7 @@ impl<'a> Normalize<'a> for ERecord<'a> { ERecord::UnderscoreField(_pos) => ERecord::Field(Position::zero()), ERecord::Colon(_) => ERecord::Colon(Position::zero()), ERecord::QuestionMark(_) => ERecord::QuestionMark(Position::zero()), + ERecord::SecondQuestionMark(_) => ERecord::SecondQuestionMark(Position::zero()), ERecord::Arrow(_) => ERecord::Arrow(Position::zero()), ERecord::Ampersand(_) => ERecord::Ampersand(Position::zero()), ERecord::Expr(inner_err, _) => { @@ -1393,6 +1394,9 @@ impl<'a> Normalize<'a> for ETypeAbilityImpl<'a> { ETypeAbilityImpl::Space(*inner_err, Position::zero()) } ETypeAbilityImpl::QuestionMark(_) => ETypeAbilityImpl::QuestionMark(Position::zero()), + ETypeAbilityImpl::SecondQuestionMark(_) => { + ETypeAbilityImpl::SecondQuestionMark(Position::zero()) + } ETypeAbilityImpl::Ampersand(_) => ETypeAbilityImpl::Ampersand(Position::zero()), ETypeAbilityImpl::Expr(inner_err, _) => { ETypeAbilityImpl::Expr(arena.alloc(inner_err.normalize(arena)), Position::zero()) @@ -1471,7 +1475,8 @@ impl<'a> Normalize<'a> for ETypeRecord<'a> { ETypeRecord::Open(_) => ETypeRecord::Open(Position::zero()), ETypeRecord::Field(_) => ETypeRecord::Field(Position::zero()), ETypeRecord::Colon(_) => ETypeRecord::Colon(Position::zero()), - ETypeRecord::Optional(_) => ETypeRecord::Optional(Position::zero()), + ETypeRecord::OptionalFirst(_) => ETypeRecord::OptionalFirst(Position::zero()), + ETypeRecord::OptionalSecond(_) => ETypeRecord::OptionalSecond(Position::zero()), ETypeRecord::Type(inner_err, _) => { ETypeRecord::Type(arena.alloc(inner_err.normalize(arena)), Position::zero()) } @@ -1491,7 +1496,8 @@ impl<'a> Normalize<'a> for PRecord<'a> { PRecord::Open(_) => PRecord::Open(Position::zero()), PRecord::Field(_) => PRecord::Field(Position::zero()), PRecord::Colon(_) => PRecord::Colon(Position::zero()), - PRecord::Optional(_) => PRecord::Optional(Position::zero()), + PRecord::OptionalFirst(_) => PRecord::OptionalFirst(Position::zero()), + PRecord::OptionalSecond(_) => PRecord::OptionalSecond(Position::zero()), PRecord::Pattern(inner_err, _) => { PRecord::Pattern(arena.alloc(inner_err.normalize(arena)), Position::zero()) } diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index acc9b53b1a..500be5bc84 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -683,6 +683,7 @@ pub enum ERecord<'a> { UnderscoreField(Position), Colon(Position), QuestionMark(Position), + SecondQuestionMark(Position), Arrow(Position), Ampersand(Position), @@ -706,6 +707,7 @@ impl<'a> ERecord<'a> { | ERecord::UnderscoreField(p) | ERecord::Colon(p) | ERecord::QuestionMark(p) + | ERecord::SecondQuestionMark(p) | ERecord::Arrow(p) | ERecord::Ampersand(p) | ERecord::Space(_, p) => Region::from_pos(*p), @@ -1107,7 +1109,8 @@ pub enum PRecord<'a> { Field(Position), Colon(Position), - Optional(Position), + OptionalFirst(Position), + OptionalSecond(Position), Pattern(&'a EPattern<'a>, Position), Expr(&'a EExpr<'a>, Position), @@ -1127,7 +1130,8 @@ impl<'a> PRecord<'a> { | PRecord::Open(p) | PRecord::Field(p) | PRecord::Colon(p) - | PRecord::Optional(p) + | PRecord::OptionalFirst(p) + | PRecord::OptionalSecond(p) | PRecord::Space(_, p) => Region::from_pos(*p), } } @@ -1244,7 +1248,8 @@ pub enum ETypeRecord<'a> { Field(Position), Colon(Position), - Optional(Position), + OptionalFirst(Position), + OptionalSecond(Position), Type(&'a EType<'a>, Position), Space(BadInputError, Position), @@ -1266,7 +1271,8 @@ impl<'a> ETypeRecord<'a> { | ETypeRecord::Open(p) | ETypeRecord::Field(p) | ETypeRecord::Colon(p) - | ETypeRecord::Optional(p) + | ETypeRecord::OptionalFirst(p) + | ETypeRecord::OptionalSecond(p) | ETypeRecord::Space(_, p) | ETypeRecord::IndentOpen(p) | ETypeRecord::IndentColon(p) @@ -1394,6 +1400,7 @@ pub enum ETypeAbilityImpl<'a> { Prefix(Position), QuestionMark(Position), + SecondQuestionMark(Position), Ampersand(Position), Expr(&'a EExpr<'a>, Position), IndentBar(Position), @@ -1416,6 +1423,7 @@ impl<'a> ETypeAbilityImpl<'a> { | ETypeAbilityImpl::Space(_, p) | ETypeAbilityImpl::Prefix(p) | ETypeAbilityImpl::QuestionMark(p) + | ETypeAbilityImpl::SecondQuestionMark(p) | ETypeAbilityImpl::Ampersand(p) | ETypeAbilityImpl::IndentBar(p) | ETypeAbilityImpl::IndentAmpersand(p) => Region::from_pos(*p), @@ -1435,6 +1443,7 @@ impl<'a> From> for ETypeAbilityImpl<'a> { ERecord::Space(s, p) => ETypeAbilityImpl::Space(s, p), ERecord::Prefix(p) => ETypeAbilityImpl::Prefix(p), ERecord::QuestionMark(p) => ETypeAbilityImpl::QuestionMark(p), + ERecord::SecondQuestionMark(p) => ETypeAbilityImpl::SecondQuestionMark(p), ERecord::Ampersand(p) => ETypeAbilityImpl::Ampersand(p), ERecord::Expr(e, p) => ETypeAbilityImpl::Expr(e, p), } diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index e1f291b4e5..e94ac3cf12 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -552,8 +552,8 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc>, PRecord<'a>> let (_, opt_loc_val, state) = optional(either( byte(b':', PRecord::Colon), and( - byte(b'?', PRecord::Optional), - optional(byte(b'?', PRecord::Optional)), + byte(b'?', PRecord::OptionalFirst), + optional(byte(b'?', PRecord::OptionalSecond)), ), )) .parse(arena, state, min_indent)?; diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 2ac4a6851b..59deeb859d 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -589,8 +589,8 @@ fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<' let (_, opt_loc_val, state) = optional(either( byte(b':', ETypeRecord::Colon), and( - byte(b'?', ETypeRecord::Optional), - optional(byte(b'?', ETypeRecord::Optional)), + byte(b'?', ETypeRecord::OptionalFirst), + optional(byte(b'?', ETypeRecord::OptionalSecond)), ), )) .parse(arena, state, min_indent)?; diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index 9fc7554fa7..4784ed0f64 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -2449,7 +2449,7 @@ fn to_precord_report<'a>( PRecord::Colon(_) => { unreachable!("because `foo` is a valid field; the colon is not required") } - PRecord::Optional(_) => { + PRecord::OptionalFirst(_) | PRecord::OptionalSecond(_) => { unreachable!("because `foo` is a valid field; the question mark is not required") } @@ -2976,7 +2976,7 @@ fn to_trecord_report<'a>( ETypeRecord::Colon(_) => { unreachable!("because `foo` is a valid field; the colon is not required") } - ETypeRecord::Optional(_) => { + ETypeRecord::OptionalFirst(_) | ETypeRecord::OptionalSecond(_) => { unreachable!("because `foo` is a valid field; the question mark is not required") }