mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-10 10:02:38 +03:00
Report an error for lookups of unexposed values
This commit is contained in:
parent
7b09232911
commit
572c7cb3dd
@ -200,22 +200,20 @@ pub fn pre_constrain_imports(
|
|||||||
|
|
||||||
match exposed_types.get(&module_id) {
|
match exposed_types.get(&module_id) {
|
||||||
Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => {
|
Some(ExposedModuleTypes::Valid(solved_types, new_aliases)) => {
|
||||||
let solved_type = solved_types.get(&symbol).unwrap_or_else(|| {
|
// If the exposed value was invalid (e.g. it didn't have
|
||||||
panic!(
|
// a corresponding definition), it won't have an entry
|
||||||
"Could not find {:?} in solved_types {:?}",
|
// in solved_types
|
||||||
loc_symbol.value, solved_types
|
if let Some(solved_type) = solved_types.get(&symbol) {
|
||||||
)
|
// TODO should this be a union?
|
||||||
});
|
for (k, v) in new_aliases.clone() {
|
||||||
|
imported_aliases.insert(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO should this be a union?
|
imported_symbols.push(Import {
|
||||||
for (k, v) in new_aliases.clone() {
|
loc_symbol,
|
||||||
imported_aliases.insert(k, v);
|
solved_type: solved_type.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
imported_symbols.push(Import {
|
|
||||||
loc_symbol,
|
|
||||||
solved_type: solved_type.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Some(ExposedModuleTypes::Invalid) => {
|
Some(ExposedModuleTypes::Invalid) => {
|
||||||
// If that module was invalid, use True constraints
|
// If that module was invalid, use True constraints
|
||||||
|
@ -29,6 +29,22 @@ pub fn type_problem<'b>(
|
|||||||
CircularType(region, symbol, overall_type) => {
|
CircularType(region, symbol, overall_type) => {
|
||||||
to_circular_report(alloc, filename, region, symbol, overall_type)
|
to_circular_report(alloc, filename, region, symbol, overall_type)
|
||||||
}
|
}
|
||||||
|
UnexposedLookup(symbol) => {
|
||||||
|
let title = "UNRECOGNIZED NAME".to_string();
|
||||||
|
let doc = alloc
|
||||||
|
.stack(vec![alloc
|
||||||
|
.reflow("The ")
|
||||||
|
.append(alloc.module(symbol.module_id()))
|
||||||
|
.append(alloc.reflow(" module does not expose anything by the name "))
|
||||||
|
.append(alloc.symbol_unqualified(symbol))])
|
||||||
|
.append(alloc.reflow("."));
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
title,
|
||||||
|
doc,
|
||||||
|
}
|
||||||
|
}
|
||||||
BadType(type_problem) => {
|
BadType(type_problem) => {
|
||||||
use roc_types::types::Problem::*;
|
use roc_types::types::Problem::*;
|
||||||
match type_problem {
|
match type_problem {
|
||||||
|
@ -68,6 +68,7 @@ pub enum TypeError {
|
|||||||
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
||||||
CircularType(Region, Symbol, ErrorType),
|
CircularType(Region, Symbol, ErrorType),
|
||||||
BadType(roc_types::types::Problem),
|
BadType(roc_types::types::Problem),
|
||||||
|
UnexposedLookup(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
@ -273,69 +274,69 @@ fn solve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Lookup(symbol, expectation, region) => {
|
Lookup(symbol, expectation, region) => {
|
||||||
let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| {
|
match env.vars_by_symbol.get(&symbol) {
|
||||||
// TODO Instead of panicking, solve this as True and record
|
Some(var) => {
|
||||||
// a TypeError ("module Foo does not expose `bar`") for later.
|
// Deep copy the vars associated with this symbol before unifying them.
|
||||||
panic!(
|
// Otherwise, suppose we have this:
|
||||||
"Could not find symbol {:?} in vars_by_symbol {:?}",
|
//
|
||||||
symbol, env.vars_by_symbol
|
// identity = \a -> a
|
||||||
)
|
//
|
||||||
});
|
// x = identity 5
|
||||||
|
//
|
||||||
// Deep copy the vars associated with this symbol before unifying them.
|
// When we call (identity 5), it's important that we not unify
|
||||||
// Otherwise, suppose we have this:
|
// 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;
|
||||||
// identity = \a -> a
|
// the type of `identity` is more general than that!
|
||||||
//
|
//
|
||||||
// x = identity 5
|
// 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
|
||||||
// When we call (identity 5), it's important that we not unify
|
// infer the type of this lookup (in this case, `Int`) without ever
|
||||||
// on identity's original vars. If we do, the type of `identity` will be
|
// having mutated the original.
|
||||||
// mutated to be `Int -> Int` instead of `a -> `, which would be incorrect;
|
//
|
||||||
// the type of `identity` is more general than that!
|
// If this Lookup is targeting a value in another module,
|
||||||
//
|
// then we copy from that module's Subs into our own. If the value
|
||||||
// Instead, we want to unify on a *copy* of its vars. If the copy unifies
|
// is being looked up in this module, then we use our Subs as both
|
||||||
// successfully (in this case, to `Int -> Int`), we can use that to
|
// the source and destination.
|
||||||
// infer the type of this lookup (in this case, `Int`) without ever
|
let actual = deep_copy_var(subs, rank, pools, *var);
|
||||||
// having mutated the original.
|
let expected = type_to_var(
|
||||||
//
|
subs,
|
||||||
// If this Lookup is targeting a value in another module,
|
rank,
|
||||||
// then we copy from that module's Subs into our own. If the value
|
pools,
|
||||||
// is being looked up in this module, then we use our Subs as both
|
cached_aliases,
|
||||||
// the source and destination.
|
expectation.get_type_ref(),
|
||||||
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 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) => {
|
None => {
|
||||||
introduce(subs, rank, pools, &vars);
|
problems.push(TypeError::UnexposedLookup(*symbol));
|
||||||
|
|
||||||
problems.push(TypeError::BadType(problem));
|
|
||||||
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user