mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Move inhabited check to subs module
This commit is contained in:
parent
ac752adc7c
commit
8a42d60ca2
2 changed files with 65 additions and 60 deletions
|
@ -393,64 +393,6 @@ fn is_inhabited_pattern(pat: &Pattern) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true iff the given type is inhabited by at least one value.
|
|
||||||
fn is_inhabited(subs: &Subs, var: Variable) -> bool {
|
|
||||||
let mut stack = vec![var];
|
|
||||||
while let Some(var) = stack.pop() {
|
|
||||||
match subs.get_content_without_compacting(var) {
|
|
||||||
Content::FlexVar(_)
|
|
||||||
| Content::RigidVar(_)
|
|
||||||
| Content::FlexAbleVar(_, _)
|
|
||||||
| Content::RigidAbleVar(_, _)
|
|
||||||
// We don't need to look into recursion vars here, because if they show up in this
|
|
||||||
// position, they *must* belong to an inhabited type. That's because
|
|
||||||
// - if the recursion var was inferred from a value, then we know there is a value of
|
|
||||||
// the given type.
|
|
||||||
// - if the recursion var comes from an explicit annotation, then it must be an a tag
|
|
||||||
// union of the form `Rec : [ R1 Rec, R2 Rec, ..., Rn Rec ]`. However, such annotations
|
|
||||||
// are determined as illegal and reported during canonicalization, because you
|
|
||||||
// cannot have a tag union without a non-recursive variant.
|
|
||||||
| Content::RecursionVar { .. } => {}
|
|
||||||
Content::LambdaSet(_) => {}
|
|
||||||
Content::Structure(structure) => match structure {
|
|
||||||
FlatType::Apply(_, args) => stack.extend(subs.get_subs_slice(*args)),
|
|
||||||
FlatType::Func(args, _, ret) => {
|
|
||||||
stack.extend(subs.get_subs_slice(*args));
|
|
||||||
stack.push(*ret);
|
|
||||||
}
|
|
||||||
FlatType::Record(fields, ext) => {
|
|
||||||
if let Ok(iter) = fields.unsorted_iterator(subs, *ext) {
|
|
||||||
let field_vars = iter.map(|(_, field)| *field.as_inner());
|
|
||||||
stack.extend(field_vars)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => {
|
|
||||||
let mut has_no_tags = true;
|
|
||||||
for (_tag, vars) in tags.unsorted_iterator(subs, *ext) {
|
|
||||||
has_no_tags = false;
|
|
||||||
stack.extend(vars);
|
|
||||||
}
|
|
||||||
if has_no_tags {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FlatType::FunctionOrTagUnion(_, _, _) => {}
|
|
||||||
FlatType::Erroneous(_) => {}
|
|
||||||
FlatType::EmptyRecord => {}
|
|
||||||
FlatType::EmptyTagUnion => {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Content::Alias(name, _, _, _) if name.module_id() == ModuleId::NUM => {},
|
|
||||||
Content::Alias(_, _, var, _) => stack.push(*var),
|
|
||||||
Content::RangedNumber(_) => {}
|
|
||||||
Content::Error => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union, TagId) {
|
fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union, TagId) {
|
||||||
let content = subs.get_content_without_compacting(whole_var);
|
let content = subs.get_content_without_compacting(whole_var);
|
||||||
|
|
||||||
|
@ -482,7 +424,7 @@ fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union,
|
||||||
let alternatives_iter = sorted_tags.into_iter().chain(opt_openness_tag.into_iter());
|
let alternatives_iter = sorted_tags.into_iter().chain(opt_openness_tag.into_iter());
|
||||||
|
|
||||||
for (index, (tag, args)) in alternatives_iter.enumerate() {
|
for (index, (tag, args)) in alternatives_iter.enumerate() {
|
||||||
let is_inhabited = args.iter().all(|v| is_inhabited(subs, *v));
|
let is_inhabited = args.iter().all(|v| subs.is_inhabited(*v));
|
||||||
|
|
||||||
if !is_inhabited {
|
if !is_inhabited {
|
||||||
// This constructor is not material; we don't need to match over it!
|
// This constructor is not material; we don't need to match over it!
|
||||||
|
|
|
@ -6,7 +6,7 @@ use roc_collections::all::{FnvMap, ImMap, ImSet, MutSet, SendMap};
|
||||||
use roc_collections::{VecMap, VecSet};
|
use roc_collections::{VecMap, VecSet};
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::{once, Iterator, Map};
|
use std::iter::{once, Iterator, Map};
|
||||||
|
|
||||||
|
@ -2117,6 +2117,11 @@ impl Subs {
|
||||||
})
|
})
|
||||||
.flat_map(|(_, lambda_set_vars)| lambda_set_vars.into_iter())
|
.flat_map(|(_, lambda_set_vars)| lambda_set_vars.into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true iff the given type is inhabited by at least one value.
|
||||||
|
pub fn is_inhabited(&self, var: Variable) -> bool {
|
||||||
|
is_inhabited(self, var)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -5406,3 +5411,61 @@ pub fn get_member_lambda_sets_at_region(subs: &Subs, var: Variable, target_regio
|
||||||
|
|
||||||
internal_error!("No lambda set at region {} found", target_region);
|
internal_error!("No lambda set at region {} found", target_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true iff the given type is inhabited by at least one value.
|
||||||
|
fn is_inhabited(subs: &Subs, var: Variable) -> bool {
|
||||||
|
let mut stack = vec![var];
|
||||||
|
while let Some(var) = stack.pop() {
|
||||||
|
match subs.get_content_without_compacting(var) {
|
||||||
|
Content::FlexVar(_)
|
||||||
|
| Content::RigidVar(_)
|
||||||
|
| Content::FlexAbleVar(_, _)
|
||||||
|
| Content::RigidAbleVar(_, _)
|
||||||
|
// We don't need to look into recursion vars here, because if they show up in this
|
||||||
|
// position, they *must* belong to an inhabited type. That's because
|
||||||
|
// - if the recursion var was inferred from a value, then we know there is a value of
|
||||||
|
// the given type.
|
||||||
|
// - if the recursion var comes from an explicit annotation, then it must be an a tag
|
||||||
|
// union of the form `Rec : [ R1 Rec, R2 Rec, ..., Rn Rec ]`. However, such annotations
|
||||||
|
// are determined as illegal and reported during canonicalization, because you
|
||||||
|
// cannot have a tag union without a non-recursive variant.
|
||||||
|
| Content::RecursionVar { .. } => {}
|
||||||
|
Content::LambdaSet(_) => {}
|
||||||
|
Content::Structure(structure) => match structure {
|
||||||
|
FlatType::Apply(_, args) => stack.extend(subs.get_subs_slice(*args)),
|
||||||
|
FlatType::Func(args, _, ret) => {
|
||||||
|
stack.extend(subs.get_subs_slice(*args));
|
||||||
|
stack.push(*ret);
|
||||||
|
}
|
||||||
|
FlatType::Record(fields, ext) => {
|
||||||
|
if let Ok(iter) = fields.unsorted_iterator(subs, *ext) {
|
||||||
|
let field_vars = iter.map(|(_, field)| *field.as_inner());
|
||||||
|
stack.extend(field_vars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => {
|
||||||
|
let mut has_no_tags = true;
|
||||||
|
for (_tag, vars) in tags.unsorted_iterator(subs, *ext) {
|
||||||
|
has_no_tags = false;
|
||||||
|
stack.extend(vars);
|
||||||
|
}
|
||||||
|
if has_no_tags {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlatType::FunctionOrTagUnion(_, _, _) => {}
|
||||||
|
FlatType::Erroneous(_) => {}
|
||||||
|
FlatType::EmptyRecord => {}
|
||||||
|
FlatType::EmptyTagUnion => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Content::Alias(name, _, _, _) if name.module_id() == ModuleId::NUM => {},
|
||||||
|
Content::Alias(_, _, var, _) => stack.push(*var),
|
||||||
|
Content::RangedNumber(_) => {}
|
||||||
|
Content::Error => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue