Suggest possible candidate on unknown imports.
## Before ``` × Type-checking ╰─▶ Unknown module field 'ValidityRaneg' in module 'aiken/transaction' ``` ## After ``` × Type-checking ╰─▶ Unknown import 'ValidityRaneg' from module 'aiken/transaction' ╭─[../stdlib/validators/tmp.ak:2:1] 2 │ use aiken/interval.{Interval, IntervalBound, IntervalBoundType} 3 │ use aiken/transaction.{ScriptContext, ValidityRaneg} · ───────────── 4 │ ╰──── help: Did you mean to import 'ValidityRange'? ```
This commit is contained in:
parent
70b1ec4324
commit
aa2a235790
|
@ -783,21 +783,13 @@ impl<'a> Environment<'a> {
|
||||||
};
|
};
|
||||||
} else if !value_imported {
|
} else if !value_imported {
|
||||||
// Error if no type or value was found with that name
|
// Error if no type or value was found with that name
|
||||||
return Err(Error::UnknownModuleField {
|
return Err(Error::unknown_module_field(
|
||||||
location: *location,
|
*location,
|
||||||
name: name.clone(),
|
name.clone(),
|
||||||
module_name: module.join("/"),
|
module.join("/"),
|
||||||
value_constructors: module_info
|
module_info.values.keys().map(|t| t.to_string()).collect(),
|
||||||
.values
|
module_info.types.keys().map(|t| t.to_string()).collect(),
|
||||||
.keys()
|
));
|
||||||
.map(|t| t.to_string())
|
|
||||||
.collect(),
|
|
||||||
type_constructors: module_info
|
|
||||||
.types
|
|
||||||
.keys()
|
|
||||||
.map(|t| t.to_string())
|
|
||||||
.collect(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,10 @@ use ordinal::Ordinal;
|
||||||
|
|
||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
|
|
||||||
use crate::ast::{BinOp, Span, TodoKind};
|
use crate::{
|
||||||
|
ast::{BinOp, Span, TodoKind},
|
||||||
|
levenshtein,
|
||||||
|
};
|
||||||
|
|
||||||
use super::Type;
|
use super::Type;
|
||||||
|
|
||||||
|
@ -175,13 +178,15 @@ pub enum Error {
|
||||||
imported_modules: Vec<String>,
|
imported_modules: Vec<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("Unknown module field\n\n{name}\n\nin module\n\n{module_name}\n")]
|
#[error("Unknown import '{name}' from module '{module_name}'\n")]
|
||||||
|
#[diagnostic()]
|
||||||
UnknownModuleField {
|
UnknownModuleField {
|
||||||
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
module_name: String,
|
module_name: String,
|
||||||
value_constructors: Vec<String>,
|
#[help]
|
||||||
type_constructors: Vec<String>,
|
hint: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("Unknown module value\n\n{name}\n")]
|
#[error("Unknown module value\n\n{name}\n")]
|
||||||
|
@ -419,6 +424,37 @@ impl Error {
|
||||||
other => other,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unknown_module_field(
|
||||||
|
location: Span,
|
||||||
|
name: String,
|
||||||
|
module_name: String,
|
||||||
|
value_constructors: Vec<String>,
|
||||||
|
type_constructors: Vec<String>,
|
||||||
|
) -> Self {
|
||||||
|
let mut candidates = vec![];
|
||||||
|
candidates.extend(value_constructors);
|
||||||
|
candidates.extend(type_constructors);
|
||||||
|
|
||||||
|
let hint = candidates
|
||||||
|
.iter()
|
||||||
|
.map(|s| (s, levenshtein::distance(&name, s)))
|
||||||
|
.min_by(|(_, a), (_, b)| a.cmp(b))
|
||||||
|
.and_then(|(suggestion, distance)| {
|
||||||
|
if distance <= 5 {
|
||||||
|
Some(format!("Did you mean to import '{suggestion}'?"))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::UnknownModuleField {
|
||||||
|
location,
|
||||||
|
name,
|
||||||
|
module_name,
|
||||||
|
hint,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
||||||
|
|
Loading…
Reference in New Issue