mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Validate derives clauses after solving
This commit is contained in:
parent
4cf87510c8
commit
a4c122d5db
11 changed files with 440 additions and 113 deletions
|
@ -32,6 +32,7 @@ use roc_problem::can::{CycleEntry, Problem, RuntimeError};
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::IllegalCycleMark;
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::AliasCommon;
|
||||
use roc_types::types::AliasKind;
|
||||
use roc_types::types::AliasVar;
|
||||
use roc_types::types::LambdaSet;
|
||||
|
@ -349,7 +350,7 @@ fn canonicalize_opaque<'a>(
|
|||
ann: &'a Loc<ast::TypeAnnotation<'a>>,
|
||||
vars: &[Loc<Lowercase>],
|
||||
derives: Option<&'a Loc<ast::Derived<'a>>>,
|
||||
) -> Result<(Alias, Vec<(Symbol, Region)>), ()> {
|
||||
) -> Result<Alias, ()> {
|
||||
let alias = canonicalize_alias(
|
||||
env,
|
||||
output,
|
||||
|
@ -381,7 +382,7 @@ fn canonicalize_opaque<'a>(
|
|||
Type::Apply(ability, args, _)
|
||||
if ability.is_builtin_ability() && args.is_empty() =>
|
||||
{
|
||||
can_derives.push((ability, region));
|
||||
can_derives.push(Loc::at(region, ability));
|
||||
}
|
||||
_ => {
|
||||
// Register the problem but keep going, we may still be able to compile the
|
||||
|
@ -391,10 +392,30 @@ fn canonicalize_opaque<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Ok((alias, can_derives))
|
||||
} else {
|
||||
Ok((alias, vec![]))
|
||||
if !can_derives.is_empty() {
|
||||
// Fresh instance of this opaque to be checked for derivability during solving.
|
||||
let fresh_inst = Type::DelayedAlias(AliasCommon {
|
||||
symbol: name.value,
|
||||
type_arguments: alias
|
||||
.type_variables
|
||||
.iter()
|
||||
.map(|_| Type::Variable(var_store.fresh()))
|
||||
.collect(),
|
||||
lambda_set_variables: alias
|
||||
.lambda_set_variables
|
||||
.iter()
|
||||
.map(|_| LambdaSet(Type::Variable(var_store.fresh())))
|
||||
.collect(),
|
||||
});
|
||||
|
||||
let old = output
|
||||
.pending_derives
|
||||
.insert(name.value, (fresh_inst, can_derives));
|
||||
debug_assert!(old.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(alias)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -550,7 +571,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
|||
derived,
|
||||
);
|
||||
|
||||
if let Ok((alias, _derives_to_check)) = alias_and_derives {
|
||||
if let Ok(alias) = alias_and_derives {
|
||||
aliases.insert(name.value, alias);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ use roc_types::types::{Alias, Category, LambdaSet, OptAbleVar, Type};
|
|||
use std::fmt::{Debug, Display};
|
||||
use std::{char, u32};
|
||||
|
||||
/// Derives that an opaque type has claimed, to checked and recorded after solving.
|
||||
pub type PendingDerives = VecMap<Symbol, (Type, Vec<Loc<Symbol>>)>;
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Output {
|
||||
pub references: References,
|
||||
|
@ -31,6 +34,7 @@ pub struct Output {
|
|||
pub introduced_variables: IntroducedVariables,
|
||||
pub aliases: VecMap<Symbol, Alias>,
|
||||
pub non_closures: VecSet<Symbol>,
|
||||
pub pending_derives: PendingDerives,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
|
@ -45,6 +49,15 @@ impl Output {
|
|||
.union_owned(other.introduced_variables);
|
||||
self.aliases.extend(other.aliases);
|
||||
self.non_closures.extend(other.non_closures);
|
||||
|
||||
{
|
||||
let expected_derives_size = self.pending_derives.len() + other.pending_derives.len();
|
||||
self.pending_derives.extend(other.pending_derives);
|
||||
debug_assert!(
|
||||
expected_derives_size == self.pending_derives.len(),
|
||||
"Derives overwritten from nested scope - something is very wrong"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::annotation::canonicalize_annotation;
|
|||
use crate::def::{canonicalize_defs, sort_can_defs, Declaration, Def};
|
||||
use crate::effect_module::HostedGeneratedFunctions;
|
||||
use crate::env::Env;
|
||||
use crate::expr::{ClosureData, Expr, Output};
|
||||
use crate::expr::{ClosureData, Expr, Output, PendingDerives};
|
||||
use crate::operator::desugar_def;
|
||||
use crate::pattern::Pattern;
|
||||
use crate::scope::Scope;
|
||||
|
@ -51,6 +51,7 @@ pub struct ModuleOutput {
|
|||
pub referenced_values: VecSet<Symbol>,
|
||||
pub referenced_types: VecSet<Symbol>,
|
||||
pub symbols_from_requires: Vec<(Loc<Symbol>, Loc<Type>)>,
|
||||
pub pending_derives: PendingDerives,
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
||||
|
@ -290,6 +291,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
PatternType::TopLevelDef,
|
||||
);
|
||||
|
||||
let pending_derives = output.pending_derives;
|
||||
|
||||
// See if any of the new idents we defined went unused.
|
||||
// If any were unused and also not exposed, report it.
|
||||
for (symbol, region) in symbols_introduced {
|
||||
|
@ -354,6 +357,11 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
let (mut declarations, mut output) = sort_can_defs(&mut env, var_store, defs, new_output);
|
||||
|
||||
debug_assert!(
|
||||
output.pending_derives.is_empty(),
|
||||
"I thought pending derives are only found during def introduction"
|
||||
);
|
||||
|
||||
let symbols_from_requires = symbols_from_requires
|
||||
.iter()
|
||||
.map(|(symbol, loc_ann)| {
|
||||
|
@ -588,6 +596,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
exposed_imports: can_exposed_imports,
|
||||
problems: env.problems,
|
||||
symbols_from_requires,
|
||||
pending_derives,
|
||||
lookups,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue