Validate derives clauses after solving

This commit is contained in:
Ayaz Hafiz 2022-05-20 15:53:47 -04:00
parent 4cf87510c8
commit a4c122d5db
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
11 changed files with 440 additions and 113 deletions

View file

@ -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);
}
}

View file

@ -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"
);
}
}
}

View file

@ -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,
}
}