Skip to content

Commit 8879a5e

Browse files
committed
Implement lpil suggestions after review.
Rename all terms related to variables: variable / functions, Var, identifiers to value(s) in code, comment and CHANGELOG.md Rename the new field in `Error::UnknownVariable` from `imported_modules_with_same_public_variable_name` to `possible_modules`. The field name was too long. Change the fold pattern with immutable accumulator to a for loop mutating a variable. Rewrite the compiler message to a "Did you mean" sentence.
1 parent 5f92807 commit 8879a5e

File tree

8 files changed

+93
-133
lines changed

8 files changed

+93
-133
lines changed

compiler-core/src/error.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,7 +2402,7 @@ but no type in scope with that name."
24022402
discarded_location,
24032403
name,
24042404
type_with_name_in_scope,
2405-
imported_modules_with_same_public_variable_name,
2405+
possible_modules,
24062406
} => {
24072407
let title = String::from("Unknown variable");
24082408
if let Some(ignored_location) = discarded_location {
@@ -2443,20 +2443,15 @@ but no type in scope with that name."
24432443
wrap_format!("The name `{name}` is not in scope here.")
24442444
};
24452445

2446-
// If there are some suggestions about variables in imported modules
2447-
// put a "consider" text after the main message
2448-
if !imported_modules_with_same_public_variable_name.is_empty() {
2449-
let consider_text = imported_modules_with_same_public_variable_name
2450-
.iter()
2451-
.fold(
2452-
String::from("Consider using one of these variables:\n\n"),
2453-
|mut acc, module_name| {
2454-
acc.push_str(&wrap_format!(" {module_name}.{name}\n"));
2455-
acc
2456-
}
2457-
);
2446+
// If there are some suggestions about public values in imported
2447+
// modules put a "did you mean" text after the main message
2448+
if !possible_modules.is_empty() {
2449+
let mut did_you_mean_text = String::from("Did you mean one of these:\n\n");
2450+
for module_name in possible_modules {
2451+
did_you_mean_text.push_str(&format!(" - {module_name}.{name}\n"));
2452+
}
24582453
text.push('\n');
2459-
text.push_str(&consider_text);
2454+
text.push_str(&did_you_mean_text);
24602455
}
24612456

24622457
text

compiler-core/src/type_.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,15 @@ impl ModuleInterface {
11031103
}
11041104
}
11051105

1106+
pub fn get_public_function(&self, name: &str, arity: usize) -> Option<&ValueConstructor> {
1107+
self.get_public_value(name).filter(|value_constructor| {
1108+
match value_constructor.type_.fn_types() {
1109+
Some((fn_arguments_type, _)) => fn_arguments_type.len() == arity,
1110+
None => false,
1111+
}
1112+
})
1113+
}
1114+
11061115
pub fn get_public_type(&self, name: &str) -> Option<&TypeConstructor> {
11071116
let type_ = self.types.get(name)?;
11081117
if type_.publicity.is_importable() {
@@ -1680,14 +1689,11 @@ pub enum FieldAccessUsage {
16801689
Other,
16811690
}
16821691

1683-
/// This is used to know when a variable is used as a value or as a call:
1684-
/// function call, a pipeline or a custom type variant constructor
1692+
/// This is used to know when a value is used as a call or not.
16851693
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1686-
pub enum VarUsage {
1687-
/// Used as `call()` or `left |> right`
1694+
pub enum ValueUsage {
1695+
/// Used as `call(..)`, `Type(..)`, `left |> right` or `left |> right(..)`
16881696
Call { arity: usize },
1689-
/// Used as `left |> right(..)`
1690-
PipelineCall,
16911697
/// Used as `variable`
16921698
Other,
16931699
}

compiler-core/src/type_/environment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ impl Environment<'_> {
488488
name: name.clone(),
489489
variables: self.local_value_names(),
490490
type_with_name_in_scope: self.module_types.keys().any(|typ| typ == name),
491-
imported_modules_with_same_public_variable_name: self
491+
possible_modules: self
492492
.imported_modules
493493
.iter()
494494
.filter_map(|(module_name, (_, module))| {

compiler-core/src/type_/error.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub enum Error {
167167
type_with_name_in_scope: bool,
168168
/// Filled with the name of imported modules when the module has public value
169169
/// with the same name as this variable
170-
imported_modules_with_same_public_variable_name: Vec<EcoString>,
170+
possible_modules: Vec<EcoString>,
171171
},
172172

173173
UnknownType {
@@ -1317,7 +1317,7 @@ pub enum UnknownValueConstructorError {
13171317
name: EcoString,
13181318
variables: Vec<EcoString>,
13191319
type_with_name_in_scope: bool,
1320-
imported_modules_with_same_public_variable_name: Vec<EcoString>,
1320+
possible_modules: Vec<EcoString>,
13211321
},
13221322

13231323
Module {
@@ -1343,14 +1343,14 @@ pub fn convert_get_value_constructor_error(
13431343
name,
13441344
variables,
13451345
type_with_name_in_scope,
1346-
imported_modules_with_same_public_variable_name,
1346+
possible_modules,
13471347
} => Error::UnknownVariable {
13481348
location,
13491349
name,
13501350
variables,
13511351
discarded_location: None,
13521352
type_with_name_in_scope,
1353-
imported_modules_with_same_public_variable_name,
1353+
possible_modules,
13541354
},
13551355

13561356
UnknownValueConstructorError::Module { name, suggestions } => Error::UnknownModule {

compiler-core/src/type_/expression.rs

Lines changed: 41 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
435435
UntypedExpr::Var { location, name, .. } => self.infer_var(
436436
name,
437437
location,
438-
VarUsage::Other,
438+
ValueUsage::Other,
439439
ReferenceRegistration::RegisterReferences,
440440
),
441441

@@ -727,7 +727,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
727727
}
728728

729729
// Helper to create a new error expr.
730-
pub(crate) fn error_expr(&mut self, location: SrcSpan) -> TypedExpr {
730+
fn error_expr(&mut self, location: SrcSpan) -> TypedExpr {
731731
TypedExpr::Invalid {
732732
location,
733733
type_: self.new_unbound_var(),
@@ -1246,11 +1246,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
12461246
}
12471247
}
12481248

1249-
pub(crate) fn infer_var(
1249+
fn infer_var(
12501250
&mut self,
12511251
name: EcoString,
12521252
location: SrcSpan,
1253-
var_usage: VarUsage,
1253+
var_usage: ValueUsage,
12541254
register_reference: ReferenceRegistration,
12551255
) -> Result<TypedExpr, Error> {
12561256
let constructor = self.do_infer_value_constructor(
@@ -1354,7 +1354,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
13541354
UntypedExpr::Var { location, name } => self.infer_var(
13551355
name,
13561356
location,
1357-
VarUsage::Other,
1357+
ValueUsage::Other,
13581358
ReferenceRegistration::DoNotRegisterReferences,
13591359
),
13601360
_ => self.infer_or_error(container),
@@ -2320,7 +2320,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
23202320
match guard {
23212321
ClauseGuard::Var { location, name, .. } => {
23222322
let constructor =
2323-
self.infer_value_constructor(&None, &name, &location, VarUsage::Other)?;
2323+
self.infer_value_constructor(&None, &name, &location, ValueUsage::Other)?;
23242324

23252325
// We cannot support all values in guard expressions as the BEAM does not
23262326
let definition_location = match &constructor.variant {
@@ -3483,7 +3483,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
34833483
module: &Option<(EcoString, SrcSpan)>,
34843484
name: &EcoString,
34853485
location: &SrcSpan,
3486-
var_usage: VarUsage,
3486+
var_usage: ValueUsage,
34873487
) -> Result<ValueConstructor, Error> {
34883488
self.do_infer_value_constructor(
34893489
module,
@@ -3499,7 +3499,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
34993499
module: &Option<(EcoString, SrcSpan)>,
35003500
name: &EcoString,
35013501
location: &SrcSpan,
3502-
var_usage: VarUsage,
3502+
var_usage: ValueUsage,
35033503
register_reference: ReferenceRegistration,
35043504
) -> Result<ValueConstructor, Error> {
35053505
let constructor = match module {
@@ -3640,7 +3640,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
36403640
&mut self,
36413641
name: &EcoString,
36423642
location: &SrcSpan,
3643-
var_usage: VarUsage,
3643+
var_usage: ValueUsage,
36443644
) -> Error {
36453645
// First try to see if this is a module alias:
36463646
// `import gleam/io`
@@ -3653,47 +3653,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
36533653
name: name.clone(),
36543654
},
36553655
None => {
3656-
let imported_modules_with_same_public_variable_name = match var_usage {
3656+
let possible_modules = match var_usage {
36573657
// This is a function call, we need to suggest a public
3658-
// variable which is a function with the correct arity
3659-
VarUsage::Call { arity } => self
3658+
// value which is a function with the correct arity
3659+
ValueUsage::Call { arity } => self
36603660
.environment
36613661
.imported_modules
36623662
.iter()
36633663
.filter_map(|(module_name, (_, module))| {
3664-
module
3665-
.get_public_value(name)
3666-
.filter(|value_constructor| {
3667-
match value_constructor.type_.fn_types() {
3668-
Some((fn_arguments_type, _)) => {
3669-
fn_arguments_type.len() == arity
3670-
}
3671-
None => false,
3672-
}
3673-
})
3674-
.map(|_| module_name)
3675-
})
3676-
.cloned()
3677-
.collect_vec(),
3678-
// This is a `Call` into a `Pipeline`. This is hard to make
3679-
// good suggestions because of the way it can be desugared.
3680-
// In this case, return every functions with the same name
3681-
// even if they have wrong arity.
3682-
VarUsage::PipelineCall => self
3683-
.environment
3684-
.imported_modules
3685-
.iter()
3686-
.filter_map(|(module_name, (_, module))| {
3687-
module
3688-
.get_public_value(name)
3689-
.filter(|value_constructor| value_constructor.type_.is_fun())
3690-
.map(|_| module_name)
3664+
module.get_public_function(name, arity).map(|_| module_name)
36913665
})
36923666
.cloned()
36933667
.collect_vec(),
36943668
// This is a reference to a variable, we need to suggest
3695-
// public variables of any type
3696-
VarUsage::Other => self
3669+
// a public value of any type
3670+
ValueUsage::Other => self
36973671
.environment
36983672
.imported_modules
36993673
.iter()
@@ -3718,7 +3692,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
37183692
.module_types
37193693
.keys()
37203694
.any(|typ| typ == name),
3721-
imported_modules_with_same_public_variable_name,
3695+
possible_modules,
37223696
}
37233697
}
37243698
}
@@ -3779,7 +3753,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
37793753
} if arguments.is_empty() => {
37803754
// Type check the record constructor
37813755
let constructor =
3782-
self.infer_value_constructor(&module, &name, &location, VarUsage::Other)?;
3756+
self.infer_value_constructor(&module, &name, &location, ValueUsage::Other)?;
37833757

37843758
let (tag, field_map) = match &constructor.variant {
37853759
ValueConstructorVariant::Record {
@@ -3822,7 +3796,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
38223796
&module,
38233797
&name,
38243798
&location,
3825-
VarUsage::Call {
3799+
ValueUsage::Call {
38263800
arity: arguments.len(),
38273801
},
38283802
)?;
@@ -3968,7 +3942,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
39683942
} => {
39693943
// Infer the type of this constant
39703944
let constructor =
3971-
self.infer_value_constructor(&module, &name, &location, VarUsage::Other)?;
3945+
self.infer_value_constructor(&module, &name, &location, ValueUsage::Other)?;
39723946
match constructor.variant {
39733947
ValueConstructorVariant::ModuleConstant { .. }
39743948
| ValueConstructorVariant::LocalConstant { .. }
@@ -4146,27 +4120,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
41464120
) -> (TypedExpr, Vec<TypedCallArg>, Arc<Type>) {
41474121
let fun = match fun {
41484122
UntypedExpr::Var { location, name } => {
4149-
// Because we are not calling infer / infer_or_error directly,
4150-
// we do not warn if there was a previous panic. Check for that
4151-
// here. Not perfect, but works.
4152-
if self.previous_panics {
4153-
self.warn_for_unreachable_code(location, PanicPosition::PreviousExpression);
4154-
}
4155-
4156-
match self.infer_var(
4157-
name,
4158-
location,
4159-
VarUsage::Call {
4160-
arity: arguments.len(),
4161-
},
4162-
ReferenceRegistration::RegisterReferences,
4163-
) {
4164-
Ok(typed_expr) => typed_expr,
4165-
Err(error) => {
4166-
self.problems.error(error);
4167-
self.error_expr(location)
4168-
}
4169-
}
4123+
self.infer_called_var(name, location, arguments.len())
41704124
}
41714125

41724126
UntypedExpr::FieldAccess {
@@ -4206,6 +4160,26 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
42064160
(fun, arguments, type_)
42074161
}
42084162

4163+
pub fn infer_called_var(
4164+
&mut self,
4165+
name: EcoString,
4166+
location: SrcSpan,
4167+
arity: usize,
4168+
) -> TypedExpr {
4169+
match self.infer_var(
4170+
name,
4171+
location,
4172+
ValueUsage::Call { arity },
4173+
ReferenceRegistration::RegisterReferences,
4174+
) {
4175+
Ok(typed_expr) => typed_expr,
4176+
Err(error) => {
4177+
self.problems.error(error);
4178+
self.error_expr(location)
4179+
}
4180+
}
4181+
}
4182+
42094183
fn infer_fn_with_call_context(
42104184
&mut self,
42114185
arguments: Vec<UntypedArg>,
@@ -4768,7 +4742,7 @@ fn is_trusted_pure_module(environment: &Environment<'_>) -> bool {
47684742
}
47694743

47704744
#[derive(Debug, Clone, Copy)]
4771-
pub(crate) enum ReferenceRegistration {
4745+
enum ReferenceRegistration {
47724746
RegisterReferences,
47734747
DoNotRegisterReferences,
47744748
}

compiler-core/src/type_/pattern.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
12591259
.module_types
12601260
.keys()
12611261
.any(|type_| type_ == &name),
1262-
imported_modules_with_same_public_variable_name: self
1262+
possible_modules: self
12631263
.environment
12641264
.imported_modules
12651265
.iter()

0 commit comments

Comments
 (0)