mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
implement standard as patterns in mono IR
This commit is contained in:
parent
726d8d80c4
commit
cf15654ee5
7 changed files with 347 additions and 128 deletions
|
@ -521,138 +521,142 @@ fn tests_at_path<'a>(
|
|||
unique
|
||||
}
|
||||
|
||||
fn test_for_pattern<'a>(pattern: &Pattern<'a>) -> Option<Test<'a>> {
|
||||
use Pattern::*;
|
||||
use Test::*;
|
||||
|
||||
let test = match pattern {
|
||||
Identifier(_) | Underscore => {
|
||||
return None;
|
||||
}
|
||||
|
||||
As(subpattern, _) => return test_for_pattern(subpattern),
|
||||
|
||||
RecordDestructure(destructs, _) => {
|
||||
// not rendered, so pick the easiest
|
||||
let union = Union {
|
||||
render_as: RenderAs::Tag,
|
||||
alternatives: vec![Ctor {
|
||||
tag_id: TagId(0),
|
||||
name: CtorName::Tag(TagName(RECORD_TAG_NAME.into())),
|
||||
arity: destructs.len(),
|
||||
}],
|
||||
};
|
||||
|
||||
let mut arguments = std::vec::Vec::new();
|
||||
|
||||
for destruct in destructs {
|
||||
match &destruct.typ {
|
||||
DestructType::Guard(guard) => {
|
||||
arguments.push((guard.clone(), destruct.layout));
|
||||
}
|
||||
DestructType::Required(_) => {
|
||||
arguments.push((Pattern::Underscore, destruct.layout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsCtor {
|
||||
tag_id: 0,
|
||||
ctor_name: CtorName::Tag(TagName(RECORD_TAG_NAME.into())),
|
||||
union,
|
||||
arguments,
|
||||
}
|
||||
}
|
||||
|
||||
NewtypeDestructure {
|
||||
tag_name,
|
||||
arguments,
|
||||
} => {
|
||||
let tag_id = 0;
|
||||
let union = Union::newtype_wrapper(CtorName::Tag(tag_name.clone()), arguments.len());
|
||||
|
||||
IsCtor {
|
||||
tag_id,
|
||||
ctor_name: CtorName::Tag(tag_name.clone()),
|
||||
union,
|
||||
arguments: arguments.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
AppliedTag {
|
||||
tag_name,
|
||||
tag_id,
|
||||
arguments,
|
||||
union,
|
||||
..
|
||||
} => IsCtor {
|
||||
tag_id: *tag_id,
|
||||
ctor_name: CtorName::Tag(tag_name.clone()),
|
||||
union: union.clone(),
|
||||
arguments: arguments.to_vec(),
|
||||
},
|
||||
|
||||
List {
|
||||
arity,
|
||||
element_layout: _,
|
||||
elements: _,
|
||||
} => IsListLen {
|
||||
bound: match arity {
|
||||
ListArity::Exact(_) => ListLenBound::Exact,
|
||||
ListArity::Slice(_, _) => ListLenBound::AtLeast,
|
||||
},
|
||||
len: arity.min_len() as _,
|
||||
},
|
||||
|
||||
Voided { .. } => internal_error!("unreachable"),
|
||||
|
||||
OpaqueUnwrap { opaque, argument } => {
|
||||
let union = Union {
|
||||
render_as: RenderAs::Tag,
|
||||
alternatives: vec![Ctor {
|
||||
tag_id: TagId(0),
|
||||
name: CtorName::Opaque(*opaque),
|
||||
arity: 1,
|
||||
}],
|
||||
};
|
||||
|
||||
IsCtor {
|
||||
tag_id: 0,
|
||||
ctor_name: CtorName::Opaque(*opaque),
|
||||
union,
|
||||
arguments: vec![(**argument).clone()],
|
||||
}
|
||||
}
|
||||
|
||||
BitLiteral { value, .. } => IsBit(*value),
|
||||
EnumLiteral { tag_id, union, .. } => IsByte {
|
||||
tag_id: *tag_id as _,
|
||||
num_alts: union.alternatives.len(),
|
||||
},
|
||||
IntLiteral(v, precision) => IsInt(*v, *precision),
|
||||
FloatLiteral(v, precision) => IsFloat(*v, *precision),
|
||||
DecimalLiteral(v) => IsDecimal(*v),
|
||||
StrLiteral(v) => IsStr(v.clone()),
|
||||
};
|
||||
|
||||
Some(test)
|
||||
}
|
||||
|
||||
fn test_at_path<'a>(
|
||||
selected_path: &[PathInstruction],
|
||||
branch: &Branch<'a>,
|
||||
) -> Option<GuardedTest<'a>> {
|
||||
use Pattern::*;
|
||||
use Test::*;
|
||||
|
||||
match branch
|
||||
let (_, pattern) = branch
|
||||
.patterns
|
||||
.iter()
|
||||
.find(|(path, _)| path == selected_path)
|
||||
{
|
||||
None => None,
|
||||
Some((_, pattern)) => {
|
||||
let test = match pattern {
|
||||
Identifier(_) | Underscore => {
|
||||
if let Guard::Guard { .. } = &branch.guard {
|
||||
// no tests for this pattern remain, but we cannot discard it yet
|
||||
// because it has a guard!
|
||||
return Some(GuardedTest::Placeholder);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
.find(|(path, _)| path == selected_path)?;
|
||||
|
||||
RecordDestructure(destructs, _) => {
|
||||
// not rendered, so pick the easiest
|
||||
let union = Union {
|
||||
render_as: RenderAs::Tag,
|
||||
alternatives: vec![Ctor {
|
||||
tag_id: TagId(0),
|
||||
name: CtorName::Tag(TagName(RECORD_TAG_NAME.into())),
|
||||
arity: destructs.len(),
|
||||
}],
|
||||
};
|
||||
|
||||
let mut arguments = std::vec::Vec::new();
|
||||
|
||||
for destruct in destructs {
|
||||
match &destruct.typ {
|
||||
DestructType::Guard(guard) => {
|
||||
arguments.push((guard.clone(), destruct.layout));
|
||||
}
|
||||
DestructType::Required(_) => {
|
||||
arguments.push((Pattern::Underscore, destruct.layout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IsCtor {
|
||||
tag_id: 0,
|
||||
ctor_name: CtorName::Tag(TagName(RECORD_TAG_NAME.into())),
|
||||
union,
|
||||
arguments,
|
||||
}
|
||||
}
|
||||
|
||||
NewtypeDestructure {
|
||||
tag_name,
|
||||
arguments,
|
||||
} => {
|
||||
let tag_id = 0;
|
||||
let union =
|
||||
Union::newtype_wrapper(CtorName::Tag(tag_name.clone()), arguments.len());
|
||||
|
||||
IsCtor {
|
||||
tag_id,
|
||||
ctor_name: CtorName::Tag(tag_name.clone()),
|
||||
union,
|
||||
arguments: arguments.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
AppliedTag {
|
||||
tag_name,
|
||||
tag_id,
|
||||
arguments,
|
||||
union,
|
||||
..
|
||||
} => IsCtor {
|
||||
tag_id: *tag_id,
|
||||
ctor_name: CtorName::Tag(tag_name.clone()),
|
||||
union: union.clone(),
|
||||
arguments: arguments.to_vec(),
|
||||
},
|
||||
|
||||
List {
|
||||
arity,
|
||||
element_layout: _,
|
||||
elements: _,
|
||||
} => IsListLen {
|
||||
bound: match arity {
|
||||
ListArity::Exact(_) => ListLenBound::Exact,
|
||||
ListArity::Slice(_, _) => ListLenBound::AtLeast,
|
||||
},
|
||||
len: arity.min_len() as _,
|
||||
},
|
||||
|
||||
Voided { .. } => internal_error!("unreachable"),
|
||||
|
||||
OpaqueUnwrap { opaque, argument } => {
|
||||
let union = Union {
|
||||
render_as: RenderAs::Tag,
|
||||
alternatives: vec![Ctor {
|
||||
tag_id: TagId(0),
|
||||
name: CtorName::Opaque(*opaque),
|
||||
arity: 1,
|
||||
}],
|
||||
};
|
||||
|
||||
IsCtor {
|
||||
tag_id: 0,
|
||||
ctor_name: CtorName::Opaque(*opaque),
|
||||
union,
|
||||
arguments: vec![(**argument).clone()],
|
||||
}
|
||||
}
|
||||
|
||||
BitLiteral { value, .. } => IsBit(*value),
|
||||
EnumLiteral { tag_id, union, .. } => IsByte {
|
||||
tag_id: *tag_id as _,
|
||||
num_alts: union.alternatives.len(),
|
||||
},
|
||||
IntLiteral(v, precision) => IsInt(*v, *precision),
|
||||
FloatLiteral(v, precision) => IsFloat(*v, *precision),
|
||||
DecimalLiteral(v) => IsDecimal(*v),
|
||||
StrLiteral(v) => IsStr(v.clone()),
|
||||
};
|
||||
|
||||
let guarded_test = GuardedTest::TestNotGuarded { test };
|
||||
|
||||
Some(guarded_test)
|
||||
match test_for_pattern(pattern) {
|
||||
Some(test) => Some(GuardedTest::TestNotGuarded { test }),
|
||||
None => {
|
||||
if let Guard::Guard { .. } = &branch.guard {
|
||||
// no tests for this pattern remain, but we cannot discard it yet
|
||||
// because it has a guard!
|
||||
Some(GuardedTest::Placeholder)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -732,6 +736,10 @@ fn to_relevant_branch_help<'a>(
|
|||
match pattern {
|
||||
Identifier(_) | Underscore => Some(branch.clone()),
|
||||
|
||||
As(subpattern, _symbol) => {
|
||||
to_relevant_branch_help(test, path, start, end, branch, *subpattern)
|
||||
}
|
||||
|
||||
RecordDestructure(destructs, _) => match test {
|
||||
IsCtor {
|
||||
ctor_name: test_name,
|
||||
|
@ -1099,6 +1107,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
|
|||
match pattern {
|
||||
Identifier(_) | Underscore => false,
|
||||
|
||||
As(subpattern, _) => needs_tests(subpattern),
|
||||
|
||||
NewtypeDestructure { .. }
|
||||
| RecordDestructure(..)
|
||||
| AppliedTag { .. }
|
||||
|
|
|
@ -7411,6 +7411,28 @@ fn store_pattern_help<'a>(
|
|||
// do nothing
|
||||
return StorePattern::NotProductive(stmt);
|
||||
}
|
||||
As(subpattern, symbol) => {
|
||||
let stored_subpattern =
|
||||
store_pattern_help(env, procs, layout_cache, subpattern, outer_symbol, stmt);
|
||||
|
||||
let mut stmt = match stored_subpattern {
|
||||
StorePattern::Productive(stmt) => stmt,
|
||||
StorePattern::NotProductive(stmt) => stmt,
|
||||
};
|
||||
|
||||
// An identifier in a pattern can define at most one specialization!
|
||||
// Remove any requested specializations for this name now, since this is the definition site.
|
||||
let specialization_symbol = procs
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
// Can happen when the symbol was never used under this body, and hence has no
|
||||
// requested specialization.
|
||||
.unwrap_or(*symbol);
|
||||
|
||||
substitute_in_exprs(env.arena, &mut stmt, specialization_symbol, outer_symbol);
|
||||
|
||||
return StorePattern::Productive(stmt);
|
||||
}
|
||||
IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
| DecimalLiteral(_)
|
||||
|
@ -9259,6 +9281,7 @@ fn call_specialized_proc<'a>(
|
|||
pub enum Pattern<'a> {
|
||||
Identifier(Symbol),
|
||||
Underscore,
|
||||
As(Box<Pattern<'a>>, Symbol),
|
||||
IntLiteral([u8; 16], IntWidth),
|
||||
FloatLiteral(u64, FloatWidth),
|
||||
DecimalLiteral([u8; 16]),
|
||||
|
@ -9316,6 +9339,7 @@ impl<'a> Pattern<'a> {
|
|||
| Pattern::BitLiteral { .. }
|
||||
| Pattern::EnumLiteral { .. }
|
||||
| Pattern::StrLiteral(_) => { /* terminal */ }
|
||||
Pattern::As(subpattern, _) => stack.push(subpattern),
|
||||
Pattern::RecordDestructure(destructs, _) => {
|
||||
for destruct in destructs {
|
||||
match &destruct.typ {
|
||||
|
@ -9394,7 +9418,12 @@ fn from_can_pattern_help<'a>(
|
|||
match can_pattern {
|
||||
Underscore => Ok(Pattern::Underscore),
|
||||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||
As(_, _) => todo!(),
|
||||
As(subpattern, symbol) => {
|
||||
let mono_subpattern =
|
||||
from_can_pattern_help(env, procs, layout_cache, &subpattern.value, assignments)?;
|
||||
|
||||
Ok(Pattern::As(Box::new(mono_subpattern), *symbol))
|
||||
}
|
||||
AbilityMemberSpecialization { ident, .. } => Ok(Pattern::Identifier(*ident)),
|
||||
IntLiteral(var, _, int_str, int, _bound) => Ok(make_num_literal_pattern(
|
||||
env,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue