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:
Agus Zubiaga 2024-01-11 18:09:01 -03:00
parent 08e6b79dca
commit 7b3317dbb6
No known key found for this signature in database
18 changed files with 334 additions and 122 deletions

View file

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