mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Update unused warnings for inline imports
Now that imports can be limited to smaller scopes than the entire module, unused import warnings need to work like unused def warnings. This commit moves unused import warnings discovery and reporting from load to canonicalization where we can track their usage per scope. This also fixes a longstanding bug where unused exposed names from an import were not reported if they were only used in a qualified manner.
This commit is contained in:
parent
08e6b79dca
commit
7b3317dbb6
18 changed files with 334 additions and 122 deletions
|
@ -1,5 +1,5 @@
|
|||
use crate::env::Env;
|
||||
use crate::procedure::References;
|
||||
use crate::procedure::{QualifiedReference, References};
|
||||
use crate::scope::{PendingAbilitiesInScope, Scope};
|
||||
use roc_collections::{ImMap, MutSet, SendMap, VecMap, VecSet};
|
||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||
|
@ -17,10 +17,43 @@ use roc_types::types::{
|
|||
pub struct Annotation {
|
||||
pub typ: Type,
|
||||
pub introduced_variables: IntroducedVariables,
|
||||
pub references: VecSet<Symbol>,
|
||||
pub references: AnnotationReferences,
|
||||
pub aliases: VecMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AnnotationReferences {
|
||||
symbols: VecSet<Symbol>,
|
||||
qualified: Vec<QualifiedReference>,
|
||||
}
|
||||
|
||||
impl AnnotationReferences {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
symbols: Default::default(),
|
||||
qualified: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, symbol: Symbol, qualified: QualifiedReference) {
|
||||
if !self.symbols.insert(symbol) {
|
||||
self.qualified.push(qualified);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_lookups(&self, references: &mut References) {
|
||||
for (symbol, qualified) in self.symbols.iter().zip(&self.qualified) {
|
||||
references.insert_type_lookup(*symbol, *qualified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AnnotationReferences {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
pub fn add_to(
|
||||
&self,
|
||||
|
@ -28,9 +61,7 @@ impl Annotation {
|
|||
references: &mut References,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
) {
|
||||
for symbol in self.references.iter() {
|
||||
references.insert_type_lookup(*symbol);
|
||||
}
|
||||
self.references.insert_lookups(references);
|
||||
|
||||
introduced_variables.union(&self.introduced_variables);
|
||||
|
||||
|
@ -291,7 +322,7 @@ pub(crate) fn canonicalize_annotation(
|
|||
annotation_for: AnnotationFor,
|
||||
) -> Annotation {
|
||||
let mut introduced_variables = IntroducedVariables::default();
|
||||
let mut references = VecSet::default();
|
||||
let mut references = AnnotationReferences::new();
|
||||
let mut aliases = VecMap::default();
|
||||
|
||||
let (annotation, region) = match annotation {
|
||||
|
@ -381,13 +412,17 @@ pub(crate) fn make_apply_symbol(
|
|||
scope: &mut Scope,
|
||||
module_name: &str,
|
||||
ident: &str,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> Result<Symbol, Type> {
|
||||
if module_name.is_empty() {
|
||||
// Since module_name was empty, this is an unqualified type.
|
||||
// Look it up in scope!
|
||||
|
||||
match scope.lookup_str(ident, region) {
|
||||
Ok(symbol) => Ok(symbol),
|
||||
Ok(symbol) => {
|
||||
references.insert(symbol, QualifiedReference::Unqualified);
|
||||
Ok(symbol)
|
||||
}
|
||||
Err(problem) => {
|
||||
env.problem(roc_problem::can::Problem::RuntimeError(problem));
|
||||
|
||||
|
@ -396,7 +431,10 @@ pub(crate) fn make_apply_symbol(
|
|||
}
|
||||
} else {
|
||||
match env.qualified_lookup(scope, module_name, ident, region) {
|
||||
Ok(symbol) => Ok(symbol),
|
||||
Ok(symbol) => {
|
||||
references.insert(symbol, QualifiedReference::Qualified);
|
||||
Ok(symbol)
|
||||
}
|
||||
Err(problem) => {
|
||||
// Either the module wasn't imported, or
|
||||
// it was imported but it doesn't expose this ident.
|
||||
|
@ -537,7 +575,7 @@ fn can_annotation_help(
|
|||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> Type {
|
||||
use roc_parse::ast::TypeAnnotation::*;
|
||||
|
||||
|
@ -580,15 +618,14 @@ fn can_annotation_help(
|
|||
Type::Function(args, Box::new(closure), Box::new(ret))
|
||||
}
|
||||
Apply(module_name, ident, type_arguments) => {
|
||||
let symbol = match make_apply_symbol(env, region, scope, module_name, ident) {
|
||||
let symbol = match make_apply_symbol(env, region, scope, module_name, ident, references)
|
||||
{
|
||||
Err(problem) => return problem,
|
||||
Ok(symbol) => symbol,
|
||||
};
|
||||
|
||||
let mut args = Vec::new();
|
||||
|
||||
references.insert(symbol);
|
||||
|
||||
if scope.abilities_store.is_ability(symbol) {
|
||||
let fresh_ty_var = find_fresh_var_name(introduced_variables);
|
||||
|
||||
|
@ -744,7 +781,7 @@ fn can_annotation_help(
|
|||
let mut vars = Vec::with_capacity(loc_vars.len());
|
||||
let mut lowercase_vars: Vec<Loc<AliasVar>> = Vec::with_capacity(loc_vars.len());
|
||||
|
||||
references.insert(symbol);
|
||||
references.insert(symbol, QualifiedReference::Unqualified);
|
||||
|
||||
for loc_var in *loc_vars {
|
||||
let var = match loc_var.value {
|
||||
|
@ -1055,7 +1092,7 @@ fn canonicalize_has_clause(
|
|||
introduced_variables: &mut IntroducedVariables,
|
||||
clause: &Loc<roc_parse::ast::ImplementsClause<'_>>,
|
||||
pending_abilities_in_scope: &PendingAbilitiesInScope,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> Result<(), Type> {
|
||||
let Loc {
|
||||
region,
|
||||
|
@ -1078,7 +1115,7 @@ fn canonicalize_has_clause(
|
|||
{
|
||||
let ability = match ability {
|
||||
TypeAnnotation::Apply(module_name, ident, _type_arguments) => {
|
||||
let symbol = make_apply_symbol(env, region, scope, module_name, ident)?;
|
||||
let symbol = make_apply_symbol(env, region, scope, module_name, ident, references)?;
|
||||
|
||||
// Ability defined locally, whose members we are constructing right now...
|
||||
if !pending_abilities_in_scope.contains_key(&symbol)
|
||||
|
@ -1096,7 +1133,6 @@ fn canonicalize_has_clause(
|
|||
}
|
||||
};
|
||||
|
||||
references.insert(ability);
|
||||
let already_seen = can_abilities.insert(ability);
|
||||
|
||||
if already_seen {
|
||||
|
@ -1130,7 +1166,7 @@ fn can_extension_type(
|
|||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
opt_ext: &Option<&Loc<TypeAnnotation>>,
|
||||
ext_problem_kind: roc_problem::can::ExtensionTypeKind,
|
||||
) -> (Type, ExtImplicitOpenness) {
|
||||
|
@ -1333,7 +1369,7 @@ fn can_assigned_fields<'a>(
|
|||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> SendMap<Lowercase, RecordField<Type>> {
|
||||
use roc_parse::ast::AssignedField::*;
|
||||
use roc_types::types::RecordField::*;
|
||||
|
@ -1448,7 +1484,7 @@ fn can_assigned_tuple_elems(
|
|||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> VecMap<usize, Type> {
|
||||
let mut elem_types = VecMap::with_capacity(elems.len());
|
||||
|
||||
|
@ -1482,7 +1518,7 @@ fn can_tags<'a>(
|
|||
var_store: &mut VarStore,
|
||||
introduced_variables: &mut IntroducedVariables,
|
||||
local_aliases: &mut VecMap<Symbol, Alias>,
|
||||
references: &mut VecSet<Symbol>,
|
||||
references: &mut AnnotationReferences,
|
||||
) -> Vec<(TagName, Vec<Type>)> {
|
||||
let mut tag_types = Vec::with_capacity(tags.len());
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::annotation::canonicalize_annotation;
|
|||
use crate::annotation::find_type_def_symbols;
|
||||
use crate::annotation::make_apply_symbol;
|
||||
use crate::annotation::AnnotationFor;
|
||||
use crate::annotation::AnnotationReferences;
|
||||
use crate::annotation::IntroducedVariables;
|
||||
use crate::annotation::OwnedNamedOrAble;
|
||||
use crate::derive;
|
||||
|
@ -358,9 +359,7 @@ fn canonicalize_alias<'a>(
|
|||
);
|
||||
|
||||
// Record all the annotation's references in output.references.lookups
|
||||
for symbol in can_ann.references {
|
||||
output.references.insert_type_lookup(symbol);
|
||||
}
|
||||
can_ann.references.insert_lookups(&mut output.references);
|
||||
|
||||
let mut can_vars: Vec<Loc<AliasVar>> = Vec::with_capacity(vars.len());
|
||||
let mut is_phantom = false;
|
||||
|
@ -704,6 +703,8 @@ fn canonicalize_opaque<'a>(
|
|||
AliasKind::Opaque,
|
||||
)?;
|
||||
|
||||
let mut references = AnnotationReferences::new();
|
||||
|
||||
let mut derived_defs = Vec::new();
|
||||
if let Some(has_abilities) = has_abilities {
|
||||
let has_abilities = has_abilities.value.collection();
|
||||
|
@ -722,7 +723,8 @@ fn canonicalize_opaque<'a>(
|
|||
// Op := {} has [Eq]
|
||||
let (ability, members) = match ability.value {
|
||||
ast::TypeAnnotation::Apply(module_name, ident, []) => {
|
||||
match make_apply_symbol(env, region, scope, module_name, ident) {
|
||||
match make_apply_symbol(env, region, scope, module_name, ident, &mut references)
|
||||
{
|
||||
Ok(ability) => {
|
||||
let opt_members = scope
|
||||
.abilities_store
|
||||
|
@ -915,6 +917,8 @@ fn canonicalize_opaque<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
references.insert_lookups(&mut output.references);
|
||||
|
||||
Ok(CanonicalizedOpaque {
|
||||
opaque_def: alias,
|
||||
derived_defs,
|
||||
|
@ -929,7 +933,12 @@ pub(crate) fn canonicalize_defs<'a>(
|
|||
scope: &mut Scope,
|
||||
loc_defs: &'a mut roc_parse::ast::Defs<'a>,
|
||||
pattern_type: PatternType,
|
||||
) -> (CanDefs, Output, MutMap<Symbol, Region>) {
|
||||
) -> (
|
||||
CanDefs,
|
||||
Output,
|
||||
MutMap<Symbol, Region>,
|
||||
Vec<IntroducedImport>,
|
||||
) {
|
||||
// Canonicalizing defs while detecting shadowing involves a multi-step process:
|
||||
//
|
||||
// 1. Go through each of the patterns.
|
||||
|
@ -979,6 +988,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
|||
env,
|
||||
var_store,
|
||||
value_def,
|
||||
region,
|
||||
scope,
|
||||
&pending_abilities_in_scope,
|
||||
&mut output,
|
||||
|
@ -1035,7 +1045,12 @@ fn canonicalize_value_defs<'a>(
|
|||
pattern_type: PatternType,
|
||||
mut aliases: VecMap<Symbol, Alias>,
|
||||
mut symbols_introduced: MutMap<Symbol, Region>,
|
||||
) -> (CanDefs, Output, MutMap<Symbol, Region>) {
|
||||
) -> (
|
||||
CanDefs,
|
||||
Output,
|
||||
MutMap<Symbol, Region>,
|
||||
Vec<IntroducedImport>,
|
||||
) {
|
||||
// Canonicalize all the patterns, record shadowing problems, and store
|
||||
// the ast::Expr values in pending_exprs for further canonicalization
|
||||
// once we've finished assembling the entire scope.
|
||||
|
@ -1045,6 +1060,8 @@ fn canonicalize_value_defs<'a>(
|
|||
let mut pending_expect_fx = Vec::with_capacity(value_defs.len());
|
||||
let mut pending_ingested_files = Vec::with_capacity(value_defs.len());
|
||||
|
||||
let mut imports_introduced = Vec::with_capacity(value_defs.len());
|
||||
|
||||
for loc_pending_def in value_defs {
|
||||
match loc_pending_def.value {
|
||||
PendingValue::Def(pending_def) => {
|
||||
|
@ -1064,7 +1081,9 @@ fn canonicalize_value_defs<'a>(
|
|||
PendingValue::ExpectFx(pending_expect) => {
|
||||
pending_expect_fx.push(pending_expect);
|
||||
}
|
||||
PendingValue::ModuleImport => { /* nothing to do */ }
|
||||
PendingValue::ModuleImport(introduced_import) => {
|
||||
imports_introduced.push(introduced_import);
|
||||
}
|
||||
PendingValue::IngestedFileImport(pending_ingested_file) => {
|
||||
pending_ingested_files.push(pending_ingested_file);
|
||||
}
|
||||
|
@ -1181,7 +1200,7 @@ fn canonicalize_value_defs<'a>(
|
|||
aliases,
|
||||
};
|
||||
|
||||
(can_defs, output, symbols_introduced)
|
||||
(can_defs, output, symbols_introduced, imports_introduced)
|
||||
}
|
||||
|
||||
struct CanonicalizedTypeDefs<'a> {
|
||||
|
@ -1395,9 +1414,9 @@ fn resolve_abilities(
|
|||
);
|
||||
|
||||
// Record all the annotation's references in output.references.lookups
|
||||
for symbol in member_annot.references {
|
||||
output.references.insert_type_lookup(symbol);
|
||||
}
|
||||
member_annot
|
||||
.references
|
||||
.insert_lookups(&mut output.references);
|
||||
|
||||
// What variables in the annotation are bound to the parent ability, and what variables
|
||||
// are bound to some other ability?
|
||||
|
@ -2470,7 +2489,7 @@ pub fn can_defs_with_return<'a>(
|
|||
loc_defs: &'a mut Defs<'a>,
|
||||
loc_ret: &'a Loc<ast::Expr<'a>>,
|
||||
) -> (Expr, Output) {
|
||||
let (unsorted, defs_output, symbols_introduced) = canonicalize_defs(
|
||||
let (unsorted, defs_output, symbols_introduced, imports_introduced) = canonicalize_defs(
|
||||
env,
|
||||
Output::default(),
|
||||
var_store,
|
||||
|
@ -2504,6 +2523,8 @@ pub fn can_defs_with_return<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
report_unused_imports(imports_introduced, &output.references, env, scope);
|
||||
|
||||
let mut loc_expr: Loc<Expr> = ret_expr;
|
||||
|
||||
for declaration in declarations.into_iter().rev() {
|
||||
|
@ -2513,6 +2534,27 @@ pub fn can_defs_with_return<'a>(
|
|||
(loc_expr.value, output)
|
||||
}
|
||||
|
||||
pub fn report_unused_imports(
|
||||
imports_introduced: Vec<IntroducedImport>,
|
||||
references: &References,
|
||||
env: &mut Env<'_>,
|
||||
scope: &mut Scope,
|
||||
) {
|
||||
for import in imports_introduced {
|
||||
if references.has_module_lookup(import.module_id) {
|
||||
for (symbol, region) in import.exposed_symbols {
|
||||
if !references.has_unqualified_type_or_value_lookup(symbol)
|
||||
&& !scope.abilities_store.is_specialization_name(symbol)
|
||||
{
|
||||
env.problem(Problem::UnusedImport(symbol, region));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
env.problem(Problem::UnusedModuleImport(import.module_id, import.region));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decl_to_let(decl: Declaration, loc_ret: Loc<Expr>) -> Loc<Expr> {
|
||||
match decl {
|
||||
Declaration::Declare(def) => {
|
||||
|
@ -2760,7 +2802,7 @@ enum PendingValue<'a> {
|
|||
Dbg(PendingExpectOrDbg<'a>),
|
||||
Expect(PendingExpectOrDbg<'a>),
|
||||
ExpectFx(PendingExpectOrDbg<'a>),
|
||||
ModuleImport,
|
||||
ModuleImport(IntroducedImport),
|
||||
IngestedFileImport(ast::IngestedFileImport<'a>),
|
||||
SignatureDefMismatch,
|
||||
}
|
||||
|
@ -2770,10 +2812,18 @@ struct PendingExpectOrDbg<'a> {
|
|||
preceding_comment: Region,
|
||||
}
|
||||
|
||||
pub struct IntroducedImport {
|
||||
module_id: ModuleId,
|
||||
region: Region,
|
||||
exposed_symbols: Vec<(Symbol, Region)>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn to_pending_value_def<'a>(
|
||||
env: &mut Env<'a>,
|
||||
var_store: &mut VarStore,
|
||||
def: &'a ast::ValueDef<'a>,
|
||||
region: Region,
|
||||
scope: &mut Scope,
|
||||
pending_abilities_in_scope: &PendingAbilitiesInScope,
|
||||
output: &mut Output,
|
||||
|
@ -2896,14 +2946,20 @@ fn to_pending_value_def<'a>(
|
|||
|
||||
scope.import_module(module_id);
|
||||
|
||||
let mut exposed_symbols;
|
||||
|
||||
match module_import.exposed {
|
||||
None => {}
|
||||
None => {
|
||||
exposed_symbols = Vec::new();
|
||||
}
|
||||
Some(exposed_kw) => {
|
||||
let exposed_ids = env
|
||||
.dep_idents
|
||||
.get(&module_id)
|
||||
.expect("Module id should have been added in load");
|
||||
|
||||
exposed_symbols = Vec::with_capacity(exposed_kw.item.len());
|
||||
|
||||
for loc_name in exposed_kw.item.items {
|
||||
let exposed_name = loc_name.value.item();
|
||||
let name = exposed_name.as_str();
|
||||
|
@ -2912,6 +2968,7 @@ fn to_pending_value_def<'a>(
|
|||
match exposed_ids.get_id(name) {
|
||||
Some(ident_id) => {
|
||||
let symbol = Symbol::new(module_id, ident_id);
|
||||
exposed_symbols.push((symbol, loc_name.region));
|
||||
|
||||
match scope.import_symbol(ident, symbol, loc_name.region) {
|
||||
Ok(()) => {}
|
||||
|
@ -2943,7 +3000,11 @@ fn to_pending_value_def<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
PendingValue::ModuleImport
|
||||
PendingValue::ModuleImport(IntroducedImport {
|
||||
module_id,
|
||||
region,
|
||||
exposed_symbols,
|
||||
})
|
||||
}
|
||||
IngestedFileImport(module_import) => PendingValue::IngestedFileImport(*module_import),
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::num::{
|
|||
int_expr_from_result, num_expr_from_result, FloatBound, IntBound, NumBound,
|
||||
};
|
||||
use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern, PermitShadows};
|
||||
use crate::procedure::References;
|
||||
use crate::procedure::{QualifiedReference, References};
|
||||
use crate::scope::Scope;
|
||||
use crate::traverse::{walk_expr, Visitor};
|
||||
use roc_collections::soa::Index;
|
||||
|
@ -882,7 +882,9 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
Ok((name, opaque_def)) => {
|
||||
let argument = Box::new(args.pop().unwrap());
|
||||
output.references.insert_type_lookup(name);
|
||||
output
|
||||
.references
|
||||
.insert_type_lookup(name, QualifiedReference::Unqualified);
|
||||
|
||||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||
freshen_opaque_def(var_store, opaque_def);
|
||||
|
@ -1193,7 +1195,9 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
Ok((name, opaque_def)) => {
|
||||
let mut output = Output::default();
|
||||
output.references.insert_type_lookup(name);
|
||||
output
|
||||
.references
|
||||
.insert_type_lookup(name, QualifiedReference::Unqualified);
|
||||
|
||||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||
freshen_opaque_def(var_store, opaque_def);
|
||||
|
@ -1877,7 +1881,9 @@ fn canonicalize_var_lookup(
|
|||
// Look it up in scope!
|
||||
match scope.lookup_str(ident, region) {
|
||||
Ok(symbol) => {
|
||||
output.references.insert_value_lookup(symbol);
|
||||
output
|
||||
.references
|
||||
.insert_value_lookup(symbol, QualifiedReference::Unqualified);
|
||||
|
||||
if scope.abilities_store.is_ability_member_name(symbol) {
|
||||
AbilityMember(
|
||||
|
@ -1900,7 +1906,9 @@ fn canonicalize_var_lookup(
|
|||
// Look it up in the env!
|
||||
match env.qualified_lookup(scope, module_name, ident, region) {
|
||||
Ok(symbol) => {
|
||||
output.references.insert_value_lookup(symbol);
|
||||
output
|
||||
.references
|
||||
.insert_value_lookup(symbol, QualifiedReference::Qualified);
|
||||
|
||||
if scope.abilities_store.is_ability_member_name(symbol) {
|
||||
AbilityMember(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, Def};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor, AnnotationReferences};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||
use crate::effect_module::HostedGeneratedFunctions;
|
||||
use crate::env::Env;
|
||||
use crate::expr::{
|
||||
|
@ -127,7 +127,6 @@ pub struct Module {
|
|||
pub exposed_imports: MutMap<Symbol, Region>,
|
||||
pub exposed_symbols: VecSet<Symbol>,
|
||||
pub referenced_values: VecSet<Symbol>,
|
||||
pub referenced_types: VecSet<Symbol>,
|
||||
/// all aliases. `bool` indicates whether it is exposed
|
||||
pub aliases: MutMap<Symbol, (bool, Alias)>,
|
||||
pub rigid_variables: RigidVariables,
|
||||
|
@ -152,7 +151,6 @@ pub struct ModuleOutput {
|
|||
pub exposed_symbols: VecSet<Symbol>,
|
||||
pub problems: Vec<Problem>,
|
||||
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,
|
||||
|
@ -363,7 +361,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let (defs, output, symbols_introduced) = canonicalize_defs(
|
||||
let (defs, output, symbols_introduced, imports_introduced) = canonicalize_defs(
|
||||
&mut env,
|
||||
Output::default(),
|
||||
var_store,
|
||||
|
@ -389,6 +387,8 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
report_unused_imports(imports_introduced, &output.references, &mut env, &mut scope);
|
||||
|
||||
for named in output.introduced_variables.named {
|
||||
rigid_variables.named.insert(named.variable, named.name);
|
||||
}
|
||||
|
@ -404,18 +404,15 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
|
||||
let mut referenced_values = VecSet::default();
|
||||
let mut referenced_types = VecSet::default();
|
||||
|
||||
// Gather up all the symbols that were referenced across all the defs' lookups.
|
||||
referenced_values.extend(output.references.value_lookups().copied());
|
||||
referenced_types.extend(output.references.type_lookups().copied());
|
||||
|
||||
// Gather up all the symbols that were referenced across all the defs' calls.
|
||||
referenced_values.extend(output.references.calls().copied());
|
||||
|
||||
// Gather up all the symbols that were referenced from other modules.
|
||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||
referenced_types.extend(env.qualified_type_lookups.iter().copied());
|
||||
|
||||
// NOTE previously we inserted builtin defs into the list of defs here
|
||||
// this is now done later, in file.rs.
|
||||
|
@ -539,7 +536,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
let annotation = crate::annotation::Annotation {
|
||||
typ: def_annotation.signature,
|
||||
introduced_variables: def_annotation.introduced_variables,
|
||||
references: Default::default(),
|
||||
references: AnnotationReferences::new(),
|
||||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
|
@ -597,7 +594,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
let annotation = crate::annotation::Annotation {
|
||||
typ: def_annotation.signature,
|
||||
introduced_variables: def_annotation.introduced_variables,
|
||||
references: Default::default(),
|
||||
references: AnnotationReferences::new(),
|
||||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
|
@ -694,14 +691,12 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
// Incorporate any remaining output.lookups entries into references.
|
||||
referenced_values.extend(output.references.value_lookups().copied());
|
||||
referenced_types.extend(output.references.type_lookups().copied());
|
||||
|
||||
// Incorporate any remaining output.calls entries into references.
|
||||
referenced_values.extend(output.references.calls().copied());
|
||||
|
||||
// Gather up all the symbols that were referenced from other modules.
|
||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||
referenced_types.extend(env.qualified_type_lookups.iter().copied());
|
||||
|
||||
let mut fix_closures_no_capture_symbols = VecSet::default();
|
||||
let mut fix_closures_closure_captures = VecMap::default();
|
||||
|
@ -797,7 +792,6 @@ pub fn canonicalize_module_defs<'a>(
|
|||
rigid_variables,
|
||||
declarations,
|
||||
referenced_values,
|
||||
referenced_types,
|
||||
exposed_imports: can_exposed_imports,
|
||||
problems: env.problems,
|
||||
symbols_from_requires,
|
||||
|
|
|
@ -446,7 +446,10 @@ pub fn canonicalize_pattern<'a>(
|
|||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||
freshen_opaque_def(var_store, opaque_def);
|
||||
|
||||
output.references.insert_type_lookup(opaque);
|
||||
output.references.insert_type_lookup(
|
||||
opaque,
|
||||
crate::procedure::QualifiedReference::Unqualified,
|
||||
);
|
||||
|
||||
Pattern::UnwrappedOpaque {
|
||||
whole_var: var_store.fresh(),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::expr::Expr;
|
||||
use crate::pattern::Pattern;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
|
@ -46,6 +46,22 @@ impl ReferencesBitflags {
|
|||
const TYPE_LOOKUP: Self = ReferencesBitflags(2);
|
||||
const CALL: Self = ReferencesBitflags(4);
|
||||
const BOUND: Self = ReferencesBitflags(8);
|
||||
const QUALIFIED: Self = ReferencesBitflags(16);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum QualifiedReference {
|
||||
Unqualified,
|
||||
Qualified,
|
||||
}
|
||||
|
||||
impl QualifiedReference {
|
||||
fn flags(&self, flags: ReferencesBitflags) -> ReferencesBitflags {
|
||||
match self {
|
||||
Self::Unqualified => flags,
|
||||
Self::Qualified => ReferencesBitflags(flags.0 | ReferencesBitflags::QUALIFIED.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -108,12 +124,12 @@ impl References {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_value_lookup(&mut self, symbol: Symbol) {
|
||||
self.insert(symbol, ReferencesBitflags::VALUE_LOOKUP);
|
||||
pub fn insert_value_lookup(&mut self, symbol: Symbol, qualified: QualifiedReference) {
|
||||
self.insert(symbol, qualified.flags(ReferencesBitflags::VALUE_LOOKUP));
|
||||
}
|
||||
|
||||
pub fn insert_type_lookup(&mut self, symbol: Symbol) {
|
||||
self.insert(symbol, ReferencesBitflags::TYPE_LOOKUP);
|
||||
pub fn insert_type_lookup(&mut self, symbol: Symbol, qualified: QualifiedReference) {
|
||||
self.insert(symbol, qualified.flags(ReferencesBitflags::TYPE_LOOKUP));
|
||||
}
|
||||
|
||||
pub fn insert_bound(&mut self, symbol: Symbol) {
|
||||
|
@ -178,7 +194,24 @@ impl References {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn has_unqualified_type_or_value_lookup(&self, symbol: Symbol) -> bool {
|
||||
let mask = ReferencesBitflags::VALUE_LOOKUP.0 | ReferencesBitflags::TYPE_LOOKUP.0;
|
||||
let it = self.symbols.iter().zip(self.bitflags.iter());
|
||||
|
||||
for (a, b) in it {
|
||||
if *a == symbol && b.0 & mask > 0 && b.0 & ReferencesBitflags::QUALIFIED.0 == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn references_type_def(&self, symbol: Symbol) -> bool {
|
||||
self.has_type_lookup(symbol)
|
||||
}
|
||||
|
||||
pub fn has_module_lookup(&self, module_id: ModuleId) -> bool {
|
||||
self.symbols.iter().any(|sym| sym.module_id() == module_id)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue