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 {
 | 
			
		||||
                        // Error if no type or value was found with that name
 | 
			
		||||
                        return Err(Error::UnknownModuleField {
 | 
			
		||||
                            location: *location,
 | 
			
		||||
                            name: name.clone(),
 | 
			
		||||
                            module_name: module.join("/"),
 | 
			
		||||
                            value_constructors: module_info
 | 
			
		||||
                                .values
 | 
			
		||||
                                .keys()
 | 
			
		||||
                                .map(|t| t.to_string())
 | 
			
		||||
                                .collect(),
 | 
			
		||||
                            type_constructors: module_info
 | 
			
		||||
                                .types
 | 
			
		||||
                                .keys()
 | 
			
		||||
                                .map(|t| t.to_string())
 | 
			
		||||
                                .collect(),
 | 
			
		||||
                        });
 | 
			
		||||
                        return Err(Error::unknown_module_field(
 | 
			
		||||
                            *location,
 | 
			
		||||
                            name.clone(),
 | 
			
		||||
                            module.join("/"),
 | 
			
		||||
                            module_info.values.keys().map(|t| t.to_string()).collect(),
 | 
			
		||||
                            module_info.types.keys().map(|t| t.to_string()).collect(),
 | 
			
		||||
                        ));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,10 @@ use ordinal::Ordinal;
 | 
			
		|||
 | 
			
		||||
use miette::Diagnostic;
 | 
			
		||||
 | 
			
		||||
use crate::ast::{BinOp, Span, TodoKind};
 | 
			
		||||
use crate::{
 | 
			
		||||
    ast::{BinOp, Span, TodoKind},
 | 
			
		||||
    levenshtein,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::Type;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +178,15 @@ pub enum Error {
 | 
			
		|||
        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 {
 | 
			
		||||
        #[label]
 | 
			
		||||
        location: Span,
 | 
			
		||||
        name: String,
 | 
			
		||||
        module_name: String,
 | 
			
		||||
        value_constructors: Vec<String>,
 | 
			
		||||
        type_constructors: Vec<String>,
 | 
			
		||||
        #[help]
 | 
			
		||||
        hint: Option<String>,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    #[error("Unknown module value\n\n{name}\n")]
 | 
			
		||||
| 
						 | 
				
			
			@ -419,6 +424,37 @@ impl Error {
 | 
			
		|||
            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)]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue