mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Validation of opaques during canonicalization
This commit is contained in:
parent
6b53692aac
commit
90de82e295
20 changed files with 546 additions and 132 deletions
|
@ -4,7 +4,7 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
|||
use roc_problem::can::RuntimeError;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{Alias, Type};
|
||||
use roc_types::types::{Alias, AliasKind, Type};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Scope {
|
||||
|
@ -51,7 +51,7 @@ impl Scope {
|
|||
recursion_variables: MutSet::default(),
|
||||
type_variables: variables,
|
||||
// TODO(opaques): replace when opaques are included in the stdlib
|
||||
is_opaque: false,
|
||||
kind: AliasKind::Structural,
|
||||
};
|
||||
|
||||
aliases.insert(symbol, alias);
|
||||
|
@ -102,6 +102,75 @@ impl Scope {
|
|||
self.aliases.get(&symbol)
|
||||
}
|
||||
|
||||
/// Check if there is an opaque type alias referenced by `opaque_ref` referenced in the
|
||||
/// current scope. E.g. `$Age` must reference an opaque `Age` declared in this module, not any
|
||||
/// other!
|
||||
pub fn lookup_opaque_ref(
|
||||
&self,
|
||||
opaque_ref: &str,
|
||||
lookup_region: Region,
|
||||
) -> Result<Symbol, RuntimeError> {
|
||||
debug_assert!(opaque_ref.starts_with('$'));
|
||||
let opaque = opaque_ref[1..].into();
|
||||
|
||||
match self.idents.get(&opaque) {
|
||||
// TODO: is it worth caching any of these results?
|
||||
Some((symbol, decl_region)) => {
|
||||
if symbol.module_id() != self.home {
|
||||
// The reference is to an opaque type declared in another module - this is
|
||||
// illegal, as opaque types can only be wrapped/unwrapped in the scope they're
|
||||
// declared.
|
||||
return Err(RuntimeError::OpaqueOutsideScope {
|
||||
opaque,
|
||||
referenced_region: lookup_region,
|
||||
imported_region: *decl_region,
|
||||
});
|
||||
}
|
||||
|
||||
match self.aliases.get(symbol) {
|
||||
None => Err(self.opaque_not_defined_error(opaque, lookup_region, None)),
|
||||
|
||||
Some(alias) => match alias.kind {
|
||||
// The reference is to a proper alias like `Age : U32`, not an opaque type!
|
||||
AliasKind::Structural => Err(self.opaque_not_defined_error(
|
||||
opaque,
|
||||
lookup_region,
|
||||
Some(alias.header_region()),
|
||||
)),
|
||||
// All is good
|
||||
AliasKind::Opaque => Ok(*symbol),
|
||||
},
|
||||
}
|
||||
}
|
||||
None => Err(self.opaque_not_defined_error(opaque, lookup_region, None)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opaque_not_defined_error(
|
||||
&self,
|
||||
opaque: Ident,
|
||||
lookup_region: Region,
|
||||
opt_defined_alias: Option<Region>,
|
||||
) -> RuntimeError {
|
||||
let opaques_in_scope = self
|
||||
.idents()
|
||||
.filter(|(_, (sym, _))| {
|
||||
self.aliases
|
||||
.get(sym)
|
||||
.map(|alias| alias.kind)
|
||||
.unwrap_or(AliasKind::Structural)
|
||||
== AliasKind::Opaque
|
||||
})
|
||||
.map(|(v, _)| v.as_ref().into())
|
||||
.collect();
|
||||
|
||||
RuntimeError::OpaqueNotDefined {
|
||||
usage: Loc::at(lookup_region, opaque),
|
||||
opaques_in_scope,
|
||||
opt_defined_alias,
|
||||
}
|
||||
}
|
||||
|
||||
/// Introduce a new ident to scope.
|
||||
///
|
||||
/// Returns Err if this would shadow an existing ident, including the
|
||||
|
@ -182,9 +251,9 @@ impl Scope {
|
|||
region: Region,
|
||||
vars: Vec<Loc<(Lowercase, Variable)>>,
|
||||
typ: Type,
|
||||
is_opaque: bool,
|
||||
kind: AliasKind,
|
||||
) {
|
||||
let alias = create_alias(name, region, vars, typ, is_opaque);
|
||||
let alias = create_alias(name, region, vars, typ, kind);
|
||||
self.aliases.insert(name, alias);
|
||||
}
|
||||
|
||||
|
@ -198,7 +267,7 @@ pub fn create_alias(
|
|||
region: Region,
|
||||
vars: Vec<Loc<(Lowercase, Variable)>>,
|
||||
typ: Type,
|
||||
is_opaque: bool,
|
||||
kind: AliasKind,
|
||||
) -> Alias {
|
||||
let roc_types::types::VariableDetail {
|
||||
type_variables,
|
||||
|
@ -234,6 +303,6 @@ pub fn create_alias(
|
|||
lambda_set_variables,
|
||||
recursion_variables,
|
||||
typ,
|
||||
is_opaque,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue