Skip to content

Commit db21bbb

Browse files
committed
Add suggestions for pipeline similar to function but with arity of 1.
At this stage, pipeline are not considered as `Call` so previous work on `UntypedExpr::Call` does not apply directly to pipeline. With this change, we handle the pipeline case when the function / constructor is not a `Call`. ```gleam 1 |> to_string ``` When there is a call in the pipeline, it is more delicate to address because something like that: ```gleam 1 |> add(2) ``` Can be desugared into two possibilities and so suggestions are not the same. The function `report_name_error` does not have enough context to make good suggestions: ```gleam add(1, 2) add(2)(1) ``` In this case, we just suggest every functions.
1 parent 54a4166 commit db21bbb

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

compiler-core/src/type_.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1666,8 +1666,10 @@ pub enum FieldAccessUsage {
16661666
/// function call, a pipeline or a custom type variant constructor
16671667
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
16681668
pub enum VarUsage {
1669-
/// Used as `variable()`
1669+
/// Used as `call()` or `left |> right`
16701670
Call { arity: usize },
1671+
/// Used as `left |> right(..)`
1672+
PipelineCall,
16711673
/// Used as `variable`
16721674
Other,
16731675
}

compiler-core/src/type_/expression.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
727727
}
728728

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

1141-
fn infer_var(
1141+
pub(crate) fn infer_var(
11421142
&mut self,
11431143
name: EcoString,
11441144
location: SrcSpan,
@@ -3555,6 +3555,22 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
35553555
})
35563556
.cloned()
35573557
.collect_vec(),
3558+
// This is a `Call` into a `Pipeline`. This is hard to make
3559+
// good suggestions because of the way it can be desugared.
3560+
// In this case, return every functions with the same name
3561+
// even if they have wrong arity.
3562+
VarUsage::PipelineCall => self
3563+
.environment
3564+
.imported_modules
3565+
.iter()
3566+
.filter_map(|(module_name, (_, module))| {
3567+
module
3568+
.get_public_value(name)
3569+
.filter(|value_constructor| value_constructor.type_.is_fun())
3570+
.map(|_| module_name)
3571+
})
3572+
.cloned()
3573+
.collect_vec(),
35583574
// This is a reference to a variable, we need to suggest
35593575
// public variables of any type
35603576
VarUsage::Other => self
@@ -4632,7 +4648,7 @@ fn is_trusted_pure_module(environment: &Environment<'_>) -> bool {
46324648
}
46334649

46344650
#[derive(Debug, Clone, Copy)]
4635-
enum ReferenceRegistration {
4651+
pub(crate) enum ReferenceRegistration {
46364652
RegisterReferences,
46374653
DoNotRegisterReferences,
46384654
}

compiler-core/src/type_/pipe.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use self::expression::CallKind;
22

3-
use super::*;
3+
use super::{expression::ReferenceRegistration, *};
44
use crate::ast::{
55
FunctionLiteralKind, ImplicitCallArgOrigin, PIPE_VARIABLE, PipelineAssignmentKind, Statement,
66
TypedPipelineAssignment, UntypedExpr,
@@ -139,17 +139,24 @@ impl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {
139139
location,
140140
..
141141
} => {
142-
let fun = match self.expr_typer.infer_or_error(*fun) {
142+
let fun_result = match *fun {
143+
UntypedExpr::Var { location, name } => self.expr_typer.infer_var(
144+
name,
145+
location,
146+
VarUsage::PipelineCall,
147+
ReferenceRegistration::RegisterReferences,
148+
),
149+
fun => self.expr_typer.infer_or_error(fun),
150+
};
151+
152+
let fun = match fun_result {
143153
Ok(fun) => fun,
144154
Err(e) => {
145155
// In case we cannot infer the function we'll
146156
// replace it with an invalid expression with an
147157
// unbound type to keep going!
148158
self.expr_typer.problems.error(e);
149-
TypedExpr::Invalid {
150-
location,
151-
type_: self.expr_typer.new_unbound_var(),
152-
}
159+
self.expr_typer.error_expr(location)
153160
}
154161
};
155162

@@ -350,16 +357,26 @@ impl<'a, 'b, 'c> PipeTyper<'a, 'b, 'c> {
350357
/// b is the `function` argument.
351358
fn infer_apply_pipe(&mut self, function: UntypedExpr) -> TypedExpr {
352359
let function_location = function.location();
353-
let function = Box::new(match self.expr_typer.infer_or_error(function) {
360+
// Need one more step for better error suggestion. If the function is
361+
// a variable / identifier, then we can suggest variables / identifier
362+
// from imported modules with the same name and same arity.
363+
let function_result = match function {
364+
UntypedExpr::Var { location, name } => self.expr_typer.infer_var(
365+
name,
366+
location,
367+
VarUsage::Call { arity: 1 },
368+
ReferenceRegistration::RegisterReferences,
369+
),
370+
_ => self.expr_typer.infer_or_error(function),
371+
};
372+
373+
let function = Box::new(match function_result {
354374
Ok(function) => function,
355375
Err(error) => {
356376
// If we cannot infer the function we put an invalid expression
357377
// in its place so we can still keep going with the other steps.
358378
self.expr_typer.problems.error(error);
359-
TypedExpr::Invalid {
360-
location: function_location,
361-
type_: self.expr_typer.new_unbound_var(),
362-
}
379+
self.expr_typer.error_expr(function_location)
363380
}
364381
});
365382

0 commit comments

Comments
 (0)