Skip to content

Commit 29ec32d

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 7264986 commit 29ec32d

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
@@ -1095,6 +1095,15 @@ impl ModuleInterface {
10951095
}
10961096
}
10971097

1098+
pub fn get_public_function(&self, name: &str, arity: usize) -> Option<&ValueConstructor> {
1099+
self.get_public_value(name).filter(|value_constructor| {
1100+
match value_constructor.type_.fn_types() {
1101+
Some((fn_arguments_type, _)) => fn_arguments_type.len() == arity,
1102+
None => false,
1103+
}
1104+
})
1105+
}
1106+
10981107
pub fn get_public_type(&self, name: &str) -> Option<&TypeConstructor> {
10991108
let type_ = self.types.get(name)?;
11001109
if type_.publicity.is_importable() {
@@ -1665,14 +1674,11 @@ pub enum FieldAccessUsage {
16651674
Other,
16661675
}
16671676

1668-
/// This is used to know when a variable is used as a value or as a call:
1669-
/// function call, a pipeline or a custom type variant constructor
1677+
/// This is used to know when a value is used as a call or not.
16701678
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1671-
pub enum VarUsage {
1672-
/// Used as `call()` or `left |> right`
1679+
pub enum ValueUsage {
1680+
/// Used as `call(..)`, `Type(..)`, `left |> right` or `left |> right(..)`
16731681
Call { arity: usize },
1674-
/// Used as `left |> right(..)`
1675-
PipelineCall,
16761682
/// Used as `variable`
16771683
Other,
16781684
}

compiler-core/src/type_/environment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ impl Environment<'_> {
483483
name: name.clone(),
484484
variables: self.local_value_names(),
485485
type_with_name_in_scope: self.module_types.keys().any(|typ| typ == name),
486-
imported_modules_with_same_public_variable_name: self
486+
possible_modules: self
487487
.imported_modules
488488
.iter()
489489
.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 {
@@ -1303,7 +1303,7 @@ pub enum UnknownValueConstructorError {
13031303
name: EcoString,
13041304
variables: Vec<EcoString>,
13051305
type_with_name_in_scope: bool,
1306-
imported_modules_with_same_public_variable_name: Vec<EcoString>,
1306+
possible_modules: Vec<EcoString>,
13071307
},
13081308

13091309
Module {
@@ -1329,14 +1329,14 @@ pub fn convert_get_value_constructor_error(
13291329
name,
13301330
variables,
13311331
type_with_name_in_scope,
1332-
imported_modules_with_same_public_variable_name,
1332+
possible_modules,
13331333
} => Error::UnknownVariable {
13341334
location,
13351335
name,
13361336
variables,
13371337
discarded_location: None,
13381338
type_with_name_in_scope,
1339-
imported_modules_with_same_public_variable_name,
1339+
possible_modules,
13401340
},
13411341

13421342
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 {
@@ -3470,7 +3470,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
34703470
module: &Option<(EcoString, SrcSpan)>,
34713471
name: &EcoString,
34723472
location: &SrcSpan,
3473-
var_usage: VarUsage,
3473+
var_usage: ValueUsage,
34743474
) -> Result<ValueConstructor, Error> {
34753475
self.do_infer_value_constructor(
34763476
module,
@@ -3486,7 +3486,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
34863486
module: &Option<(EcoString, SrcSpan)>,
34873487
name: &EcoString,
34883488
location: &SrcSpan,
3489-
var_usage: VarUsage,
3489+
var_usage: ValueUsage,
34903490
register_reference: ReferenceRegistration,
34913491
) -> Result<ValueConstructor, Error> {
34923492
let constructor = match module {
@@ -3627,7 +3627,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
36273627
&mut self,
36283628
name: &EcoString,
36293629
location: &SrcSpan,
3630-
var_usage: VarUsage,
3630+
var_usage: ValueUsage,
36313631
) -> Error {
36323632
// First try to see if this is a module alias:
36333633
// `import gleam/io`
@@ -3640,47 +3640,21 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
36403640
name: name.clone(),
36413641
},
36423642
None => {
3643-
let imported_modules_with_same_public_variable_name = match var_usage {
3643+
let possible_modules = match var_usage {
36443644
// This is a function call, we need to suggest a public
3645-
// variable which is a function with the correct arity
3646-
VarUsage::Call { arity } => self
3645+
// value which is a function with the correct arity
3646+
ValueUsage::Call { arity } => self
36473647
.environment
36483648
.imported_modules
36493649
.iter()
36503650
.filter_map(|(module_name, (_, module))| {
3651-
module
3652-
.get_public_value(name)
3653-
.filter(|value_constructor| {
3654-
match value_constructor.type_.fn_types() {
3655-
Some((fn_arguments_type, _)) => {
3656-
fn_arguments_type.len() == arity
3657-
}
3658-
None => false,
3659-
}
3660-
})
3661-
.map(|_| module_name)
3662-
})
3663-
.cloned()
3664-
.collect_vec(),
3665-
// This is a `Call` into a `Pipeline`. This is hard to make
3666-
// good suggestions because of the way it can be desugared.
3667-
// In this case, return every functions with the same name
3668-
// even if they have wrong arity.
3669-
VarUsage::PipelineCall => self
3670-
.environment
3671-
.imported_modules
3672-
.iter()
3673-
.filter_map(|(module_name, (_, module))| {
3674-
module
3675-
.get_public_value(name)
3676-
.filter(|value_constructor| value_constructor.type_.is_fun())
3677-
.map(|_| module_name)
3651+
module.get_public_function(name, arity).map(|_| module_name)
36783652
})
36793653
.cloned()
36803654
.collect_vec(),
36813655
// This is a reference to a variable, we need to suggest
3682-
// public variables of any type
3683-
VarUsage::Other => self
3656+
// a public value of any type
3657+
ValueUsage::Other => self
36843658
.environment
36853659
.imported_modules
36863660
.iter()
@@ -3705,7 +3679,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
37053679
.module_types
37063680
.keys()
37073681
.any(|typ| typ == name),
3708-
imported_modules_with_same_public_variable_name,
3682+
possible_modules,
37093683
}
37103684
}
37113685
}
@@ -3766,7 +3740,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
37663740
} if arguments.is_empty() => {
37673741
// Type check the record constructor
37683742
let constructor =
3769-
self.infer_value_constructor(&module, &name, &location, VarUsage::Other)?;
3743+
self.infer_value_constructor(&module, &name, &location, ValueUsage::Other)?;
37703744

37713745
let (tag, field_map) = match &constructor.variant {
37723746
ValueConstructorVariant::Record {
@@ -3809,7 +3783,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
38093783
&module,
38103784
&name,
38113785
&location,
3812-
VarUsage::Call {
3786+
ValueUsage::Call {
38133787
arity: arguments.len(),
38143788
},
38153789
)?;
@@ -3955,7 +3929,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
39553929
} => {
39563930
// Infer the type of this constant
39573931
let constructor =
3958-
self.infer_value_constructor(&module, &name, &location, VarUsage::Other)?;
3932+
self.infer_value_constructor(&module, &name, &location, ValueUsage::Other)?;
39593933
match constructor.variant {
39603934
ValueConstructorVariant::ModuleConstant { .. }
39613935
| ValueConstructorVariant::LocalConstant { .. }
@@ -4133,27 +4107,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
41334107
) -> (TypedExpr, Vec<TypedCallArg>, Arc<Type>) {
41344108
let fun = match fun {
41354109
UntypedExpr::Var { location, name } => {
4136-
// Because we are not calling infer / infer_or_error directly,
4137-
// we do not warn if there was a previous panic. Check for that
4138-
// here. Not perfect, but works.
4139-
if self.previous_panics {
4140-
self.warn_for_unreachable_code(location, PanicPosition::PreviousExpression);
4141-
}
4142-
4143-
match self.infer_var(
4144-
name,
4145-
location,
4146-
VarUsage::Call {
4147-
arity: arguments.len(),
4148-
},
4149-
ReferenceRegistration::RegisterReferences,
4150-
) {
4151-
Ok(typed_expr) => typed_expr,
4152-
Err(error) => {
4153-
self.problems.error(error);
4154-
self.error_expr(location)
4155-
}
4156-
}
4110+
self.infer_called_var(name, location, arguments.len())
41574111
}
41584112

41594113
UntypedExpr::FieldAccess {
@@ -4193,6 +4147,26 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
41934147
(fun, arguments, type_)
41944148
}
41954149

4150+
pub fn infer_called_var(
4151+
&mut self,
4152+
name: EcoString,
4153+
location: SrcSpan,
4154+
arity: usize,
4155+
) -> TypedExpr {
4156+
match self.infer_var(
4157+
name,
4158+
location,
4159+
ValueUsage::Call { arity },
4160+
ReferenceRegistration::RegisterReferences,
4161+
) {
4162+
Ok(typed_expr) => typed_expr,
4163+
Err(error) => {
4164+
self.problems.error(error);
4165+
self.error_expr(location)
4166+
}
4167+
}
4168+
}
4169+
41964170
fn infer_fn_with_call_context(
41974171
&mut self,
41984172
arguments: Vec<UntypedArg>,
@@ -4755,7 +4729,7 @@ fn is_trusted_pure_module(environment: &Environment<'_>) -> bool {
47554729
}
47564730

47574731
#[derive(Debug, Clone, Copy)]
4758-
pub(crate) enum ReferenceRegistration {
4732+
enum ReferenceRegistration {
47594733
RegisterReferences,
47604734
DoNotRegisterReferences,
47614735
}

compiler-core/src/type_/pattern.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
12521252
.module_types
12531253
.keys()
12541254
.any(|type_| type_ == &name),
1255-
imported_modules_with_same_public_variable_name: self
1255+
possible_modules: self
12561256
.environment
12571257
.imported_modules
12581258
.iter()

0 commit comments

Comments
 (0)