Skip to content

Commit ace5809

Browse files
committed
fix(analyse): warn if a function definition shadows an imported one
1 parent e7ca347 commit ace5809

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

compiler-core/src/analyse.rs

+9
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,15 @@ impl<'a, A> ModuleAnalyzer<'a, A> {
248248
}
249249

250250
for f in &statements.functions {
251+
let (name_location, name) = f.name.clone().expect("A module's function must be named");
252+
if env.unqualified_imported_names.contains_key(&name) {
253+
self.problems
254+
.warning(Warning::TopLevelDefinitionShadowsImport {
255+
location: name_location,
256+
name,
257+
});
258+
}
259+
251260
if let Err(error) = self.register_value_from_function(f, &mut env) {
252261
return self.all_errors(error);
253262
}

compiler-core/src/type_/error.rs

+8
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,13 @@ pub enum Warning {
979979
truncation: BitArraySegmentTruncation,
980980
location: SrcSpan,
981981
},
982+
983+
/// Top-level definition should not shadow an imported one.
984+
/// This includes type imports and function imports.
985+
TopLevelDefinitionShadowsImport {
986+
location: SrcSpan,
987+
name: EcoString,
988+
},
982989
}
983990

984991
#[derive(Debug, Eq, Copy, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
@@ -1202,6 +1209,7 @@ impl Warning {
12021209
| Warning::FeatureRequiresHigherGleamVersion { location, .. }
12031210
| Warning::JavaScriptIntUnsafe { location, .. }
12041211
| Warning::AssertLiteralValue { location, .. }
1212+
| Warning::TopLevelDefinitionShadowsImport { location, .. }
12051213
| Warning::BitArraySegmentTruncatedValue { location, .. } => *location,
12061214
}
12071215
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
source: compiler-core/src/type_/tests/warnings.rs
3+
expression: "\nimport one.{foo}\nfn foo(x) {\n let _ = x + 1\n}\npub fn main() {\n let _ = foo(1)\n}\n"
4+
---
5+
----- SOURCE CODE
6+
-- one.gleam
7+
pub fn foo(x) { let _ = x }
8+
9+
-- main.gleam
10+
11+
import one.{foo}
12+
fn foo(x) {
13+
let _ = x + 1
14+
}
15+
pub fn main() {
16+
let _ = foo(1)
17+
}
18+
19+
20+
----- WARNING
21+
warning: Unused imported value
22+
┌─ /src/warning/wrn.gleam:2:13
23+
24+
2import one.{foo}
25+
^^^ This imported value is never used
26+
27+
Hint: You can safely remove it.
28+
29+
warning: Definition of "foo" shadows an imported item
30+
┌─ /src/warning/wrn.gleam:3:4
31+
32+
3fn foo(x) {
33+
^^^
34+
35+
The imported item could not be used anyway.
36+
Hint: You could remove the imported item.

compiler-core/src/type_/tests/warnings.rs

+16
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,22 @@ pub const make_two = one.Two
458458
);
459459
}
460460

461+
#[test]
462+
fn shadow_imported_function() {
463+
assert_warning!(
464+
("thepackage", "one", "pub fn foo(x) { let _ = x }"),
465+
"
466+
import one.{foo}
467+
fn foo(x) {
468+
let _ = x + 1
469+
}
470+
pub fn main() {
471+
let _ = foo(1)
472+
}
473+
"
474+
);
475+
}
476+
461477
// https://github.com/gleam-lang/gleam/issues/2050
462478
#[test]
463479
fn double_unary_integer_literal() {

compiler-core/src/warning.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,21 @@ can already tell whether it will be true or false.",
12761276
extra_labels: Vec::new(),
12771277
}),
12781278
},
1279+
type_::Warning::TopLevelDefinitionShadowsImport { location, name } => Diagnostic {
1280+
title: format!("Definition of \"{name}\" shadows an imported item"),
1281+
text: wrap("The imported item could not be used anyway."),
1282+
hint: Some("You could remove the imported item.".into()),
1283+
level: diagnostic::Level::Warning,
1284+
location: Some(Location {
1285+
src: src.clone(),
1286+
path: path.to_path_buf(),
1287+
label: diagnostic::Label {
1288+
text: None,
1289+
span: *location,
1290+
},
1291+
extra_labels: vec![],
1292+
}),
1293+
},
12791294
},
12801295

12811296
Warning::DeprecatedEnvironmentVariable { variable } => {

0 commit comments

Comments
 (0)