mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Report an error for lookups of unexposed values
This commit is contained in:
parent
7b09232911
commit
572c7cb3dd
3 changed files with 88 additions and 73 deletions
|
@ -68,6 +68,7 @@ pub enum TypeError {
|
|||
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
||||
CircularType(Region, Symbol, ErrorType),
|
||||
BadType(roc_types::types::Problem),
|
||||
UnexposedLookup(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -273,69 +274,69 @@ fn solve(
|
|||
}
|
||||
}
|
||||
Lookup(symbol, expectation, region) => {
|
||||
let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| {
|
||||
// TODO Instead of panicking, solve this as True and record
|
||||
// a TypeError ("module Foo does not expose `bar`") for later.
|
||||
panic!(
|
||||
"Could not find symbol {:?} in vars_by_symbol {:?}",
|
||||
symbol, env.vars_by_symbol
|
||||
)
|
||||
});
|
||||
|
||||
// Deep copy the vars associated with this symbol before unifying them.
|
||||
// Otherwise, suppose we have this:
|
||||
//
|
||||
// identity = \a -> a
|
||||
//
|
||||
// x = identity 5
|
||||
//
|
||||
// When we call (identity 5), it's important that we not unify
|
||||
// on identity's original vars. If we do, the type of `identity` will be
|
||||
// mutated to be `Int -> Int` instead of `a -> `, which would be incorrect;
|
||||
// the type of `identity` is more general than that!
|
||||
//
|
||||
// Instead, we want to unify on a *copy* of its vars. If the copy unifies
|
||||
// successfully (in this case, to `Int -> Int`), we can use that to
|
||||
// infer the type of this lookup (in this case, `Int`) without ever
|
||||
// having mutated the original.
|
||||
//
|
||||
// If this Lookup is targeting a value in another module,
|
||||
// then we copy from that module's Subs into our own. If the value
|
||||
// is being looked up in this module, then we use our Subs as both
|
||||
// the source and destination.
|
||||
let actual = deep_copy_var(subs, rank, pools, var);
|
||||
let expected = type_to_var(
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
cached_aliases,
|
||||
expectation.get_type_ref(),
|
||||
);
|
||||
match unify(subs, actual, expected) {
|
||||
Success(vars) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
Failure(vars, actual_type, expected_type) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
let problem = TypeError::BadExpr(
|
||||
*region,
|
||||
Category::Lookup(*symbol),
|
||||
actual_type,
|
||||
expectation.clone().replace(expected_type),
|
||||
match env.vars_by_symbol.get(&symbol) {
|
||||
Some(var) => {
|
||||
// Deep copy the vars associated with this symbol before unifying them.
|
||||
// Otherwise, suppose we have this:
|
||||
//
|
||||
// identity = \a -> a
|
||||
//
|
||||
// x = identity 5
|
||||
//
|
||||
// When we call (identity 5), it's important that we not unify
|
||||
// on identity's original vars. If we do, the type of `identity` will be
|
||||
// mutated to be `Int -> Int` instead of `a -> `, which would be incorrect;
|
||||
// the type of `identity` is more general than that!
|
||||
//
|
||||
// Instead, we want to unify on a *copy* of its vars. If the copy unifies
|
||||
// successfully (in this case, to `Int -> Int`), we can use that to
|
||||
// infer the type of this lookup (in this case, `Int`) without ever
|
||||
// having mutated the original.
|
||||
//
|
||||
// If this Lookup is targeting a value in another module,
|
||||
// then we copy from that module's Subs into our own. If the value
|
||||
// is being looked up in this module, then we use our Subs as both
|
||||
// the source and destination.
|
||||
let actual = deep_copy_var(subs, rank, pools, *var);
|
||||
let expected = type_to_var(
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
cached_aliases,
|
||||
expectation.get_type_ref(),
|
||||
);
|
||||
match unify(subs, actual, expected) {
|
||||
Success(vars) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
problems.push(problem);
|
||||
state
|
||||
}
|
||||
|
||||
state
|
||||
Failure(vars, actual_type, expected_type) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
let problem = TypeError::BadExpr(
|
||||
*region,
|
||||
Category::Lookup(*symbol),
|
||||
actual_type,
|
||||
expectation.clone().replace(expected_type),
|
||||
);
|
||||
|
||||
problems.push(problem);
|
||||
|
||||
state
|
||||
}
|
||||
BadType(vars, problem) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
problems.push(TypeError::BadType(problem));
|
||||
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
BadType(vars, problem) => {
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
problems.push(TypeError::BadType(problem));
|
||||
None => {
|
||||
problems.push(TypeError::UnexposedLookup(*symbol));
|
||||
|
||||
state
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue