mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
report unexposed values
This commit is contained in:
parent
802f821782
commit
dc5eec189c
8 changed files with 114 additions and 13 deletions
|
@ -1,6 +1,7 @@
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use inlinable_string::InlinableString;
|
use inlinable_string::InlinableString;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
|
@ -113,7 +114,7 @@ impl<'a> Env<'a> {
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
}
|
}
|
||||||
None => Err(RuntimeError::ValueNotExposed {
|
None => Err(RuntimeError::ValueNotExposed {
|
||||||
module_name,
|
module_name: ModuleName::from(module_name),
|
||||||
ident,
|
ident,
|
||||||
region,
|
region,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -2782,7 +2782,25 @@ pub fn with_hole<'a>(
|
||||||
use crate::layout::UnionVariant::*;
|
use crate::layout::UnionVariant::*;
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
let variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
||||||
|
|
||||||
|
let variant = match res_variant {
|
||||||
|
Ok(cached) => cached,
|
||||||
|
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||||
|
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||||
|
"UnresolvedTypeVar {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Err(LayoutProblem::Erroneous) => {
|
||||||
|
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||||
|
"Erroneous {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match variant {
|
match variant {
|
||||||
Never => unreachable!(
|
Never => unreachable!(
|
||||||
|
@ -4581,9 +4599,23 @@ fn from_can_when<'a>(
|
||||||
}
|
}
|
||||||
let opt_branches = to_opt_branches(env, region, branches, layout_cache);
|
let opt_branches = to_opt_branches(env, region, branches, layout_cache);
|
||||||
|
|
||||||
let cond_layout = layout_cache
|
let cond_layout = match layout_cache.from_var(env.arena, cond_var, env.subs) {
|
||||||
.from_var(env.arena, cond_var, env.subs)
|
Ok(cached) => cached,
|
||||||
.unwrap_or_else(|err| panic!("TODO turn this into a RuntimeError {:?}", err));
|
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||||
|
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||||
|
"UnresolvedTypeVar {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Err(LayoutProblem::Erroneous) => {
|
||||||
|
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||||
|
"Erroneous {} line {}",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let ret_layout = layout_cache
|
let ret_layout = layout_cache
|
||||||
.from_var(env.arena, expr_var, env.subs)
|
.from_var(env.arena, expr_var, env.subs)
|
||||||
|
@ -6039,7 +6071,15 @@ fn from_can_pattern_help<'a>(
|
||||||
use crate::exhaustive::Union;
|
use crate::exhaustive::Union;
|
||||||
use crate::layout::UnionVariant::*;
|
use crate::layout::UnionVariant::*;
|
||||||
|
|
||||||
let variant = crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs);
|
let res_variant = crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs);
|
||||||
|
|
||||||
|
let variant = match res_variant {
|
||||||
|
Ok(cached) => cached,
|
||||||
|
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||||
|
return Err(RuntimeError::UnresolvedTypeVar)
|
||||||
|
}
|
||||||
|
Err(LayoutProblem::Erroneous) => return Err(RuntimeError::ErroneousType),
|
||||||
|
};
|
||||||
|
|
||||||
let result = match variant {
|
let result = match variant {
|
||||||
Never => unreachable!(
|
Never => unreachable!(
|
||||||
|
|
|
@ -1324,7 +1324,11 @@ impl<'a> WrappedVariant<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union_sorted_tags<'a>(arena: &'a Bump, var: Variable, subs: &Subs) -> UnionVariant<'a> {
|
pub fn union_sorted_tags<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
var: Variable,
|
||||||
|
subs: &Subs,
|
||||||
|
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
||||||
let var =
|
let var =
|
||||||
if let Content::RecursionVar { structure, .. } = subs.get_without_compacting(var).content {
|
if let Content::RecursionVar { structure, .. } = subs.get_without_compacting(var).content {
|
||||||
structure
|
structure
|
||||||
|
@ -1338,10 +1342,11 @@ pub fn union_sorted_tags<'a>(arena: &'a Bump, var: Variable, subs: &Subs) -> Uni
|
||||||
let opt_rec_var = get_recursion_var(subs, var);
|
let opt_rec_var = get_recursion_var(subs, var);
|
||||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs)
|
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs)
|
||||||
}
|
}
|
||||||
|
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
||||||
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
||||||
};
|
};
|
||||||
|
|
||||||
result
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_recursion_var(subs: &Subs, var: Variable) -> Option<Variable> {
|
fn get_recursion_var(subs: &Subs, var: Variable) -> Option<Variable> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use inlinable_string::InlinableString;
|
use inlinable_string::InlinableString;
|
||||||
use roc_collections::all::MutSet;
|
use roc_collections::all::MutSet;
|
||||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
use roc_module::ident::{Ident, Lowercase, ModuleName, TagName};
|
||||||
use roc_module::operator::BinOp;
|
use roc_module::operator::BinOp;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_parse::ast::Base;
|
use roc_parse::ast::Base;
|
||||||
|
@ -117,9 +117,13 @@ pub enum RuntimeError {
|
||||||
UnsupportedPattern(Region),
|
UnsupportedPattern(Region),
|
||||||
// Example: when 1 is 1.X -> 32
|
// Example: when 1 is 1.X -> 32
|
||||||
MalformedPattern(MalformedPatternProblem, Region),
|
MalformedPattern(MalformedPatternProblem, Region),
|
||||||
|
|
||||||
|
UnresolvedTypeVar,
|
||||||
|
ErroneousType,
|
||||||
|
|
||||||
LookupNotInScope(Located<InlinableString>, MutSet<Box<str>>),
|
LookupNotInScope(Located<InlinableString>, MutSet<Box<str>>),
|
||||||
ValueNotExposed {
|
ValueNotExposed {
|
||||||
module_name: InlinableString,
|
module_name: ModuleName,
|
||||||
ident: InlinableString,
|
ident: InlinableString,
|
||||||
region: Region,
|
region: Region,
|
||||||
},
|
},
|
||||||
|
|
|
@ -344,6 +344,11 @@ fn pretty_runtime_error<'b>(
|
||||||
unreachable!("")
|
unreachable!("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeError::UnresolvedTypeVar | RuntimeError::ErroneousType => {
|
||||||
|
// only generated during layout generation
|
||||||
|
unreachable!("")
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeError::Shadowing {
|
RuntimeError::Shadowing {
|
||||||
original_region,
|
original_region,
|
||||||
shadow,
|
shadow,
|
||||||
|
@ -443,7 +448,20 @@ fn pretty_runtime_error<'b>(
|
||||||
RuntimeError::UnsupportedPattern(_) => {
|
RuntimeError::UnsupportedPattern(_) => {
|
||||||
todo!("unsupported patterns are currently not parsed!")
|
todo!("unsupported patterns are currently not parsed!")
|
||||||
}
|
}
|
||||||
RuntimeError::ValueNotExposed { .. } => todo!("value not exposed"),
|
RuntimeError::ValueNotExposed { module_name, ident, region } => {
|
||||||
|
alloc.stack(vec![
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow("The "),
|
||||||
|
alloc.module_name(module_name),
|
||||||
|
alloc.reflow(" module does not expose a "),
|
||||||
|
alloc.string(ident.to_string()),
|
||||||
|
alloc.reflow(" value:"),
|
||||||
|
]),
|
||||||
|
alloc.region(region),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RuntimeError::ModuleNotImported {
|
RuntimeError::ModuleNotImported {
|
||||||
module_name,
|
module_name,
|
||||||
imported_modules,
|
imported_modules,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use inlinable_string::InlinableString;
|
use inlinable_string::InlinableString;
|
||||||
use roc_module::ident::Ident;
|
use roc_module::ident::Ident;
|
||||||
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
use roc_module::ident::{Lowercase, ModuleName, TagName, Uppercase};
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -316,6 +316,17 @@ impl<'a> RocDocAllocator<'a> {
|
||||||
self.text(name).annotate(Annotation::Module)
|
self.text(name).annotate(Annotation::Module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn module_name(&'a self, name: ModuleName) -> DocBuilder<'a, Self, Annotation> {
|
||||||
|
let name = if name.is_empty() {
|
||||||
|
// Render the app module as "app"
|
||||||
|
"app".to_string()
|
||||||
|
} else {
|
||||||
|
name.as_str().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.text(name).annotate(Annotation::Module)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inlinable_string(&'a self, s: InlinableString) -> DocBuilder<'a, Self, Annotation> {
|
pub fn inlinable_string(&'a self, s: InlinableString) -> DocBuilder<'a, Self, Annotation> {
|
||||||
self.text(format!("{}", s)).annotate(Annotation::Module)
|
self.text(format!("{}", s)).annotate(Annotation::Module)
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,27 @@ mod test_reporting {
|
||||||
.replace(UNDERLINE_CODE, "<underline>")
|
.replace(UNDERLINE_CODE, "<underline>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn value_not_exposed() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
List.foobar 1 2
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
── SYNTAX PROBLEM ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
The List module does not expose a foobar value:
|
||||||
|
|
||||||
|
1│ List.foobar 1 2
|
||||||
|
^^^^^^^^^^^
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn report_unused_def() {
|
fn report_unused_def() {
|
||||||
report_problem_as(
|
report_problem_as(
|
||||||
|
|
|
@ -12,6 +12,7 @@ use inlinable_string::InlinableString;
|
||||||
use roc_can::expr::Recursive;
|
use roc_can::expr::Recursive;
|
||||||
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::operator::CalledVia;
|
use roc_module::operator::CalledVia;
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
|
@ -178,7 +179,7 @@ impl<'a> Env<'a> {
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
}
|
}
|
||||||
None => Err(RuntimeError::ValueNotExposed {
|
None => Err(RuntimeError::ValueNotExposed {
|
||||||
module_name,
|
module_name: ModuleName::from(module_name),
|
||||||
ident,
|
ident,
|
||||||
region,
|
region,
|
||||||
}),
|
}),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue