Skip to content

Commit 51181ce

Browse files
giacomocavalierilpil
authored andcommitted
Make sure to reject variable sized string segment patterns
With aliases now supported in bit array segments analysis was not updated to reject aliases that ended up being the same as a variable length string pattern: `_ as a:utf8` should be rejected just like `a:utf8` is.
1 parent c390fff commit 51181ce

File tree

5 files changed

+75
-4
lines changed

5 files changed

+75
-4
lines changed

compiler-core/src/ast.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,28 @@ impl Endianness {
23742374
}
23752375
}
23762376

2377+
impl<Type> BitArraySegment<Pattern<Type>, Type> {
2378+
/// Returns the value of the pattern unwrapping any assign pattern.
2379+
///
2380+
pub fn value_unwrapping_assign(&self) -> &Pattern<Type> {
2381+
match self.value.as_ref() {
2382+
Pattern::Assign { pattern, .. } => pattern,
2383+
Pattern::Int { .. }
2384+
| Pattern::Float { .. }
2385+
| Pattern::String { .. }
2386+
| Pattern::Variable { .. }
2387+
| Pattern::VarUsage { .. }
2388+
| Pattern::Discard { .. }
2389+
| Pattern::List { .. }
2390+
| Pattern::Constructor { .. }
2391+
| Pattern::Tuple { .. }
2392+
| Pattern::BitArray { .. }
2393+
| Pattern::StringPrefix { .. }
2394+
| Pattern::Invalid { .. } => self.value.as_ref(),
2395+
}
2396+
}
2397+
}
2398+
23772399
impl<Value> BitArraySegment<Value, Arc<Type>> {
23782400
#[must_use]
23792401
pub fn has_native_option(&self) -> bool {

compiler-core/src/type_/pattern.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use num_bigint::BigInt;
88
///
99
use super::*;
1010
use crate::{
11-
analyse::{Inferred, name::check_name_case},
11+
analyse::{self, Inferred, name::check_name_case},
1212
ast::{
1313
AssignName, BitArrayOption, ImplicitCallArgOrigin, Layer, UntypedPatternBitArraySegment,
1414
},
@@ -290,7 +290,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
290290
// implicitly considered utf-8 encoded strings, while floats are
291291
// implicitly given the float type option.
292292
if !segment.has_type_option() {
293-
match segment.value.as_ref() {
293+
match segment.value_unwrapping_assign() {
294294
Pattern::String { location, .. } => {
295295
self.track_feature_usage(FeatureKind::UnannotatedUtf8StringSegment, *location);
296296
segment.options.push(BitArrayOption::Utf8 {
@@ -312,8 +312,8 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
312312
let options: Vec<_> = segment
313313
.options
314314
.into_iter()
315-
.map(|o| {
316-
crate::analyse::infer_bit_array_option(o, |value, type_| {
315+
.map(|option| {
316+
analyse::infer_bit_array_option(option, |value, type_| {
317317
Ok(self.unify(value, type_, None))
318318
})
319319
})
@@ -369,6 +369,13 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
369369
}
370370

371371
let type_ = match segment.value.deref() {
372+
Pattern::Assign { pattern, .. } if pattern.is_discard() && segment_type.is_string() => {
373+
self.error(Error::BitArraySegmentError {
374+
error: bit_array::ErrorType::VariableUtfSegmentInPattern,
375+
location: segment.location,
376+
});
377+
self.environment.new_unbound_var()
378+
}
372379
Pattern::Variable { .. } if segment_type.is_string() => {
373380
self.error(Error::BitArraySegmentError {
374381
error: bit_array::ErrorType::VariableUtfSegmentInPattern,

compiler-core/src/type_/tests/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ fn bit_array_segment_type_does_not_allow_size_utf32() {
164164
assert_error!("case <<1>> { <<1:utf32-size(5)>> -> 1 }");
165165
}
166166

167+
#[test]
168+
fn bit_array_segment_type_does_not_allow_variable_string() {
169+
assert_error!("case <<>> { <<a:utf8>> -> 1 _ -> 2 }");
170+
}
171+
172+
#[test]
173+
fn bit_array_segment_type_does_not_allow_aliased_variable_string() {
174+
assert_error!("case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }");
175+
}
176+
167177
#[test]
168178
fn bit_array_segment_unit_no_size() {
169179
assert_error!("let x = <<1:unit(5)>> x");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
source: compiler-core/src/type_/tests/errors.rs
3+
expression: "case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }"
4+
---
5+
----- SOURCE CODE
6+
case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }
7+
8+
----- ERROR
9+
error: Invalid bit array segment
10+
┌─ /src/one/two.gleam:1:15
11+
12+
1case <<>> { <<_ as a:utf8>> -> 1 _ -> 2 }
13+
^^^^^^^^^^^ This cannot be a variable
14+
15+
Hint: in patterns utf8, utf16, and utf32 must be an exact string.
16+
See: https://tour.gleam.run/data-types/bit-arrays/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
source: compiler-core/src/type_/tests/errors.rs
3+
expression: "case <<>> { <<a:utf8>> -> 1 _ -> 2 }"
4+
---
5+
----- SOURCE CODE
6+
case <<>> { <<a:utf8>> -> 1 _ -> 2 }
7+
8+
----- ERROR
9+
error: Invalid bit array segment
10+
┌─ /src/one/two.gleam:1:15
11+
12+
1case <<>> { <<a:utf8>> -> 1 _ -> 2 }
13+
^^^^^^ This cannot be a variable
14+
15+
Hint: in patterns utf8, utf16, and utf32 must be an exact string.
16+
See: https://tour.gleam.run/data-types/bit-arrays/

0 commit comments

Comments
 (0)