mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 19:32:17 +00:00
Use Opaque over Alias
This commit is contained in:
parent
73cd5b8c7c
commit
c859ce0b23
3 changed files with 90 additions and 14 deletions
|
@ -28,6 +28,7 @@ use roc_module::symbol::ModuleId;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::ast;
|
use roc_parse::ast;
|
||||||
use roc_parse::ast::AbilityMember;
|
use roc_parse::ast::AbilityMember;
|
||||||
|
use roc_parse::ast::AssignedField;
|
||||||
use roc_parse::ast::Defs;
|
use roc_parse::ast::Defs;
|
||||||
use roc_parse::ast::ExtractSpaces;
|
use roc_parse::ast::ExtractSpaces;
|
||||||
use roc_parse::ast::TypeHeader;
|
use roc_parse::ast::TypeHeader;
|
||||||
|
@ -41,6 +42,8 @@ use roc_types::types::AliasCommon;
|
||||||
use roc_types::types::AliasKind;
|
use roc_types::types::AliasKind;
|
||||||
use roc_types::types::AliasVar;
|
use roc_types::types::AliasVar;
|
||||||
use roc_types::types::LambdaSet;
|
use roc_types::types::LambdaSet;
|
||||||
|
use roc_types::types::Opaque;
|
||||||
|
use roc_types::types::OpaqueSupports;
|
||||||
use roc_types::types::OptAbleType;
|
use roc_types::types::OptAbleType;
|
||||||
use roc_types::types::{Alias, Type};
|
use roc_types::types::{Alias, Type};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -426,7 +429,7 @@ fn canonicalize_opaque<'a>(
|
||||||
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
||||||
vars: &[Loc<Lowercase>],
|
vars: &[Loc<Lowercase>],
|
||||||
has_abilities: Option<&'a Loc<ast::HasAbilities<'a>>>,
|
has_abilities: Option<&'a Loc<ast::HasAbilities<'a>>>,
|
||||||
) -> Result<Alias, ()> {
|
) -> Result<Opaque, ()> {
|
||||||
let alias = canonicalize_alias(
|
let alias = canonicalize_alias(
|
||||||
env,
|
env,
|
||||||
output,
|
output,
|
||||||
|
@ -442,24 +445,72 @@ fn canonicalize_opaque<'a>(
|
||||||
if let Some(has_abilities) = has_abilities {
|
if let Some(has_abilities) = has_abilities {
|
||||||
let has_abilities = has_abilities.value.collection();
|
let has_abilities = has_abilities.value.collection();
|
||||||
|
|
||||||
let mut can_abilities = vec![];
|
let mut derived_abilities = vec![];
|
||||||
|
let mut supported_abilities = vec![];
|
||||||
|
|
||||||
for has_ability in has_abilities.items {
|
for has_ability in has_abilities.items {
|
||||||
let region = has_ability.region;
|
let region = has_ability.region;
|
||||||
let (ability, _impls) = match has_ability.value.extract_spaces().item {
|
let (ability, opt_impls) = match has_ability.value.extract_spaces().item {
|
||||||
ast::HasAbility::HasAbility { ability, impls } => (ability, impls),
|
ast::HasAbility::HasAbility { ability, impls } => (ability, impls),
|
||||||
_ => internal_error!("spaces not extracted"),
|
_ => internal_error!("spaces not extracted"),
|
||||||
};
|
};
|
||||||
match ability.value {
|
match ability.value {
|
||||||
ast::TypeAnnotation::Apply(module_name, ident, []) => {
|
ast::TypeAnnotation::Apply(module_name, ident, []) => {
|
||||||
match make_apply_symbol(env, region, scope, module_name, ident) {
|
match make_apply_symbol(env, region, scope, module_name, ident) {
|
||||||
Ok(ability) if ability.is_builtin_ability() => {
|
Ok(ability) => {
|
||||||
can_abilities.push(Loc::at(region, ability));
|
if let Some(impls) = opt_impls {
|
||||||
}
|
// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
Ok(_) => {
|
// pub enum HasImpls<'a> {
|
||||||
// Register the problem but keep going, we may still be able to compile the
|
// // `{ eq: myEq }`
|
||||||
// program even if a derive is missing.
|
// HasImpls(Collection<'a, Loc<AssignedField<'a, TypeAnnotation<'a>>>>),
|
||||||
env.problem(Problem::IllegalDerive(region));
|
|
||||||
|
// // We preserve this for the formatter; canonicalization ignores it.
|
||||||
|
// SpaceBefore(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
// SpaceAfter(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
// }
|
||||||
|
let mut impl_map: VecMap<Symbol, Symbol> = VecMap::default();
|
||||||
|
|
||||||
|
for loc_field in impls.extract_spaces().item.items {
|
||||||
|
match loc_field.value {
|
||||||
|
AssignedField::LabelOnly(label) => {
|
||||||
|
let sym: Symbol = todo!();
|
||||||
|
|
||||||
|
impl_map.insert(sym, sym);
|
||||||
|
}
|
||||||
|
AssignedField::RequiredValue(
|
||||||
|
label,
|
||||||
|
_spaces,
|
||||||
|
Loc {
|
||||||
|
value: Expr::Var(var_name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let key_sym: Symbol = todo!(); // label
|
||||||
|
let value_sym: Symbol = todo!(); // var_name
|
||||||
|
|
||||||
|
impl_map.insert(key_sym, value_sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
supported_abilities.push(OpaqueSupports::Implemented {
|
||||||
|
ability_name: ability,
|
||||||
|
impls: impl_map,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if ability.is_builtin_ability() {
|
||||||
|
derived_abilities.push(Loc::at(region, ability));
|
||||||
|
supported_abilities.push(OpaqueSupports::Derived(ability));
|
||||||
|
} else {
|
||||||
|
// There was no record specified of functions to use for
|
||||||
|
// members, but also this isn't a builtin ability, so we don't
|
||||||
|
// know how to auto-derive it.
|
||||||
|
//
|
||||||
|
// Register the problem but keep going, we may still be able to compile the
|
||||||
|
// program even if a derive is missing.
|
||||||
|
env.problem(Problem::IllegalDerive(region));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// This is bad apply; an error will have been reported for it
|
// This is bad apply; an error will have been reported for it
|
||||||
|
@ -475,7 +526,7 @@ fn canonicalize_opaque<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !can_abilities.is_empty() {
|
if !derived_abilities.is_empty() {
|
||||||
// Fresh instance of this opaque to be checked for derivability during solving.
|
// Fresh instance of this opaque to be checked for derivability during solving.
|
||||||
let fresh_inst = Type::DelayedAlias(AliasCommon {
|
let fresh_inst = Type::DelayedAlias(AliasCommon {
|
||||||
symbol: name.value,
|
symbol: name.value,
|
||||||
|
@ -493,7 +544,7 @@ fn canonicalize_opaque<'a>(
|
||||||
|
|
||||||
let old = output
|
let old = output
|
||||||
.pending_derives
|
.pending_derives
|
||||||
.insert(name.value, (fresh_inst, can_abilities));
|
.insert(name.value, (fresh_inst, derived_abilities));
|
||||||
debug_assert!(old.is_none());
|
debug_assert!(old.is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -437,7 +437,7 @@ pub struct HasClause<'a> {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum HasImpls<'a> {
|
pub enum HasImpls<'a> {
|
||||||
// `{ eq: myEq }`
|
// `{ eq: myEq }`
|
||||||
HasImpls(Collection<'a, Loc<AssignedField<'a, TypeAnnotation<'a>>>>),
|
HasImpls(Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>),
|
||||||
|
|
||||||
// We preserve this for the formatter; canonicalization ignores it.
|
// We preserve this for the formatter; canonicalization ignores it.
|
||||||
SpaceBefore(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
SpaceBefore(&'a HasImpls<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::subs::{
|
||||||
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
|
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
|
||||||
};
|
};
|
||||||
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
|
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||||
|
use roc_collections::VecMap;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
|
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
|
||||||
|
@ -2055,7 +2056,31 @@ impl From<&AliasVar> for OptAbleVar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Opaque {
|
||||||
|
pub region: Region,
|
||||||
|
pub type_variables: Vec<Loc<AliasVar>>,
|
||||||
|
|
||||||
|
/// lambda set variables, e.g. the one annotating the arrow in
|
||||||
|
/// a |c|-> b
|
||||||
|
pub lambda_set_variables: Vec<LambdaSet>,
|
||||||
|
pub recursion_variables: MutSet<Variable>,
|
||||||
|
pub typ: Type,
|
||||||
|
pub kind: AliasKind,
|
||||||
|
|
||||||
|
pub supports: Vec<OpaqueSupports>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OpaqueSupports {
|
||||||
|
Derived(Symbol),
|
||||||
|
Implemented {
|
||||||
|
ability_name: Symbol,
|
||||||
|
impls: VecMap<Symbol, Symbol>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Alias {
|
pub struct Alias {
|
||||||
pub region: Region,
|
pub region: Region,
|
||||||
pub type_variables: Vec<Loc<AliasVar>>,
|
pub type_variables: Vec<Loc<AliasVar>>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue