Remove broken compile-time overload system (#9677)

# Description

This PR removes the compile-time overload system. Unfortunately, this
system never worked correctly because in a gradual type system where
types can be `Any`, you don't have enough information to correctly
resolve function calls with overloads. These resolutions must be done at
runtime, if they're supported.

That said, there's a bit of work that needs to go into resolving
input/output types (here overloads do not execute separate commands, but
the same command and each overload explains how each output type
corresponds to input types).

This PR also removes the type scope, which would give incorrect answers
in cases where multiple subexpressions were used in a pipeline.

# User-Facing Changes

Finishes removing compile-time overloads. These were only used in a few
places in the code base, but it's possible it may impact user code. I'll
mark this as breaking change so we can review.

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
JT 2023-07-14 07:05:03 +12:00 committed by GitHub
parent 99329f14a3
commit 30904bd095
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 445 deletions

View File

@ -9,7 +9,7 @@ use nu_protocol::report_error;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
Config, PipelineData, ShellError, Span, Type, Value, Config, PipelineData, ShellError, Span, Value,
}; };
use nu_utils::stdout_write_all_and_flush; use nu_utils::stdout_write_all_and_flush;
@ -102,7 +102,7 @@ pub fn evaluate_file(
trace!("parsing file: {}", file_path_str); trace!("parsing file: {}", file_path_str);
let _ = parse(&mut working_set, Some(file_path_str), &file, false); let _ = parse(&mut working_set, Some(file_path_str), &file, false);
if working_set.find_decl(b"main", &Type::Any).is_some() { if working_set.find_decl(b"main").is_some() {
let args = format!("main {}", args.join(" ")); let args = format!("main {}", args.join(" "));
if !eval_source( if !eval_source(

View File

@ -52,7 +52,7 @@ pub struct ScopeData<'e, 's> {
engine_state: &'e EngineState, engine_state: &'e EngineState,
stack: &'s Stack, stack: &'s Stack,
vars_map: HashMap<&'e Vec<u8>, &'e usize>, vars_map: HashMap<&'e Vec<u8>, &'e usize>,
decls_map: HashMap<&'e (Vec<u8>, Type), &'e usize>, decls_map: HashMap<&'e Vec<u8>, &'e usize>,
modules_map: HashMap<&'e Vec<u8>, &'e usize>, modules_map: HashMap<&'e Vec<u8>, &'e usize>,
visibility: Visibility, visibility: Visibility,
} }
@ -108,7 +108,7 @@ impl<'e, 's> ScopeData<'e, 's> {
pub fn collect_commands(&self, span: Span) -> Vec<Value> { pub fn collect_commands(&self, span: Span) -> Vec<Value> {
let mut commands = vec![]; let mut commands = vec![];
for ((command_name, _), decl_id) in &self.decls_map { for (command_name, decl_id) in &self.decls_map {
if self.visibility.is_decl_id_visible(decl_id) if self.visibility.is_decl_id_visible(decl_id)
&& !self.engine_state.get_decl(**decl_id).is_alias() && !self.engine_state.get_decl(**decl_id).is_alias()
{ {
@ -488,7 +488,7 @@ impl<'e, 's> ScopeData<'e, 's> {
pub fn collect_externs(&self, span: Span) -> Vec<Value> { pub fn collect_externs(&self, span: Span) -> Vec<Value> {
let mut externals = vec![]; let mut externals = vec![];
for ((command_name, _), decl_id) in &self.decls_map { for (command_name, decl_id) in &self.decls_map {
let decl = self.engine_state.get_decl(**decl_id); let decl = self.engine_state.get_decl(**decl_id);
if decl.is_known_external() { if decl.is_known_external() {

View File

@ -235,7 +235,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expressio
// Parsing the spans and checking that they match the register signature // Parsing the spans and checking that they match the register signature
// Using a parsed call makes more sense than checking for how many spans are in the call // Using a parsed call makes more sense than checking for how many spans are in the call
// Also, by creating a call, it can be checked if it matches the declaration signature // Also, by creating a call, it can be checked if it matches the declaration signature
let (call, call_span) = match working_set.find_decl(b"for", &Type::Nothing) { let (call, call_span) = match working_set.find_decl(b"for") {
None => { None => {
working_set.error(ParseError::UnknownState( working_set.error(ParseError::UnknownState(
"internal error: for declaration not found".into(), "internal error: for declaration not found".into(),
@ -359,7 +359,7 @@ pub fn parse_def(
// Parsing the spans and checking that they match the register signature // Parsing the spans and checking that they match the register signature
// Using a parsed call makes more sense than checking for how many spans are in the call // Using a parsed call makes more sense than checking for how many spans are in the call
// Also, by creating a call, it can be checked if it matches the declaration signature // Also, by creating a call, it can be checked if it matches the declaration signature
let (call, call_span) = match working_set.find_decl(&def_call, &Type::Nothing) { let (call, call_span) = match working_set.find_decl(&def_call) {
None => { None => {
working_set.error(ParseError::UnknownState( working_set.error(ParseError::UnknownState(
"internal error: def declaration not found".into(), "internal error: def declaration not found".into(),
@ -548,7 +548,7 @@ pub fn parse_extern(
// Parsing the spans and checking that they match the register signature // Parsing the spans and checking that they match the register signature
// Using a parsed call makes more sense than checking for how many spans are in the call // Using a parsed call makes more sense than checking for how many spans are in the call
// Also, by creating a call, it can be checked if it matches the declaration signature // Also, by creating a call, it can be checked if it matches the declaration signature
let (call, call_span) = match working_set.find_decl(&extern_call, &Type::Nothing) { let (call, call_span) = match working_set.find_decl(&extern_call) {
None => { None => {
working_set.error(ParseError::UnknownState( working_set.error(ParseError::UnknownState(
"internal error: def declaration not found".into(), "internal error: def declaration not found".into(),
@ -739,7 +739,7 @@ pub fn parse_alias(
return Pipeline::from_vec(vec![garbage(*span)]); return Pipeline::from_vec(vec![garbage(*span)]);
} }
if let Some(decl_id) = working_set.find_decl(b"alias", &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(b"alias") {
let (command_spans, rest_spans) = spans.split_at(split_id); let (command_spans, rest_spans) = spans.split_at(split_id);
let original_starting_error_count = working_set.parse_errors.len(); let original_starting_error_count = working_set.parse_errors.len();
@ -941,7 +941,7 @@ pub fn parse_export_in_block(
b"export".to_vec() b"export".to_vec()
}; };
if let Some(decl_id) = working_set.find_decl(&full_name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(&full_name) {
let ParsedInternalCall { call, output, .. } = parse_internal_call( let ParsedInternalCall { call, output, .. } = parse_internal_call(
working_set, working_set,
if full_name == b"export" { if full_name == b"export" {
@ -1035,7 +1035,7 @@ pub fn parse_export_in_module(
return (garbage_pipeline(spans), vec![]); return (garbage_pipeline(spans), vec![]);
}; };
let export_decl_id = if let Some(id) = working_set.find_decl(b"export", &Type::Nothing) { let export_decl_id = if let Some(id) = working_set.find_decl(b"export") {
id id
} else { } else {
working_set.error(ParseError::InternalError( working_set.error(ParseError::InternalError(
@ -1064,16 +1064,15 @@ pub fn parse_export_in_module(
}; };
let pipeline = parse_def(working_set, &lite_command, Some(module_name)); let pipeline = parse_def(working_set, &lite_command, Some(module_name));
let export_def_decl_id = let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") {
if let Some(id) = working_set.find_decl(b"export def", &Type::Nothing) { id
id } else {
} else { working_set.error(ParseError::InternalError(
working_set.error(ParseError::InternalError( "missing 'export def' command".into(),
"missing 'export def' command".into(), export_span,
export_span, ));
)); return (garbage_pipeline(spans), vec![]);
return (garbage_pipeline(spans), vec![]); };
};
// Trying to warp the 'def' call into the 'export def' in a very clumsy way // Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(PipelineElement::Expression( if let Some(PipelineElement::Expression(
@ -1101,7 +1100,7 @@ pub fn parse_export_in_module(
let decl_name = working_set.get_span_contents(*decl_name_span); let decl_name = working_set.get_span_contents(*decl_name_span);
let decl_name = trim_quotes(decl_name); let decl_name = trim_quotes(decl_name);
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(decl_name) {
result.push(Exportable::Decl { result.push(Exportable::Decl {
name: decl_name.to_vec(), name: decl_name.to_vec(),
id: decl_id, id: decl_id,
@ -1123,16 +1122,16 @@ pub fn parse_export_in_module(
}; };
let pipeline = parse_def(working_set, &lite_command, Some(module_name)); let pipeline = parse_def(working_set, &lite_command, Some(module_name));
let export_def_decl_id = let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env")
if let Some(id) = working_set.find_decl(b"export def-env", &Type::Nothing) { {
id id
} else { } else {
working_set.error(ParseError::InternalError( working_set.error(ParseError::InternalError(
"missing 'export def-env' command".into(), "missing 'export def-env' command".into(),
export_span, export_span,
)); ));
return (garbage_pipeline(spans), vec![]); return (garbage_pipeline(spans), vec![]);
}; };
// Trying to warp the 'def' call into the 'export def' in a very clumsy way // Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(PipelineElement::Expression( if let Some(PipelineElement::Expression(
@ -1162,7 +1161,7 @@ pub fn parse_export_in_module(
}; };
let decl_name = trim_quotes(decl_name); let decl_name = trim_quotes(decl_name);
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(decl_name) {
result.push(Exportable::Decl { result.push(Exportable::Decl {
name: decl_name.to_vec(), name: decl_name.to_vec(),
id: decl_id, id: decl_id,
@ -1183,16 +1182,15 @@ pub fn parse_export_in_module(
}; };
let pipeline = parse_extern(working_set, &lite_command, Some(module_name)); let pipeline = parse_extern(working_set, &lite_command, Some(module_name));
let export_def_decl_id = let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export extern") {
if let Some(id) = working_set.find_decl(b"export extern", &Type::Nothing) { id
id } else {
} else { working_set.error(ParseError::InternalError(
working_set.error(ParseError::InternalError( "missing 'export extern' command".into(),
"missing 'export extern' command".into(), export_span,
export_span, ));
)); return (garbage_pipeline(spans), vec![]);
return (garbage_pipeline(spans), vec![]); };
};
// Trying to warp the 'def' call into the 'export def' in a very clumsy way // Trying to warp the 'def' call into the 'export def' in a very clumsy way
if let Some(PipelineElement::Expression( if let Some(PipelineElement::Expression(
@ -1222,7 +1220,7 @@ pub fn parse_export_in_module(
}; };
let decl_name = trim_quotes(decl_name); let decl_name = trim_quotes(decl_name);
if let Some(decl_id) = working_set.find_decl(decl_name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(decl_name) {
result.push(Exportable::Decl { result.push(Exportable::Decl {
name: decl_name.to_vec(), name: decl_name.to_vec(),
id: decl_id, id: decl_id,
@ -1243,16 +1241,16 @@ pub fn parse_export_in_module(
}; };
let pipeline = parse_alias(working_set, &lite_command, Some(module_name)); let pipeline = parse_alias(working_set, &lite_command, Some(module_name));
let export_alias_decl_id = let export_alias_decl_id = if let Some(id) = working_set.find_decl(b"export alias")
if let Some(id) = working_set.find_decl(b"export alias", &Type::Nothing) { {
id id
} else { } else {
working_set.error(ParseError::InternalError( working_set.error(ParseError::InternalError(
"missing 'export alias' command".into(), "missing 'export alias' command".into(),
export_span, export_span,
)); ));
return (garbage_pipeline(spans), vec![]); return (garbage_pipeline(spans), vec![]);
}; };
// Trying to warp the 'alias' call into the 'export alias' in a very clumsy way // Trying to warp the 'alias' call into the 'export alias' in a very clumsy way
if let Some(PipelineElement::Expression( if let Some(PipelineElement::Expression(
@ -1282,7 +1280,7 @@ pub fn parse_export_in_module(
}; };
let alias_name = trim_quotes(alias_name); let alias_name = trim_quotes(alias_name);
if let Some(alias_id) = working_set.find_decl(alias_name, &Type::Nothing) { if let Some(alias_id) = working_set.find_decl(alias_name) {
result.push(Exportable::Decl { result.push(Exportable::Decl {
name: alias_name.to_vec(), name: alias_name.to_vec(),
id: alias_id, id: alias_id,
@ -1303,16 +1301,15 @@ pub fn parse_export_in_module(
}; };
let (pipeline, exportables) = parse_use(working_set, &lite_command.parts); let (pipeline, exportables) = parse_use(working_set, &lite_command.parts);
let export_use_decl_id = let export_use_decl_id = if let Some(id) = working_set.find_decl(b"export use") {
if let Some(id) = working_set.find_decl(b"export use", &Type::Nothing) { id
id } else {
} else { working_set.error(ParseError::InternalError(
working_set.error(ParseError::InternalError( "missing 'export use' command".into(),
"missing 'export use' command".into(), export_span,
export_span, ));
)); return (garbage_pipeline(spans), vec![]);
return (garbage_pipeline(spans), vec![]); };
};
// Trying to warp the 'use' call into the 'export use' in a very clumsy way // Trying to warp the 'use' call into the 'export use' in a very clumsy way
if let Some(PipelineElement::Expression( if let Some(PipelineElement::Expression(
@ -1341,7 +1338,7 @@ pub fn parse_export_in_module(
parse_module(working_set, lite_command, Some(module_name)); parse_module(working_set, lite_command, Some(module_name));
let export_module_decl_id = let export_module_decl_id =
if let Some(id) = working_set.find_decl(b"export module", &Type::Nothing) { if let Some(id) = working_set.find_decl(b"export module") {
id id
} else { } else {
working_set.error(ParseError::InternalError( working_set.error(ParseError::InternalError(
@ -1446,7 +1443,7 @@ pub fn parse_export_env(
return (garbage_pipeline(spans), None); return (garbage_pipeline(spans), None);
} }
let call = match working_set.find_decl(b"export-env", &Type::Nothing) { let call = match working_set.find_decl(b"export-env") {
Some(decl_id) => { Some(decl_id) => {
let ParsedInternalCall { call, output } = let ParsedInternalCall { call, output } =
parse_internal_call(working_set, spans[0], &[spans[1]], decl_id); parse_internal_call(working_set, spans[0], &[spans[1]], decl_id);
@ -1958,7 +1955,7 @@ pub fn parse_module(
1 1
}; };
let (call, call_span) = match working_set.find_decl(b"module", &Type::Nothing) { let (call, call_span) = match working_set.find_decl(b"module") {
Some(decl_id) => { Some(decl_id) => {
let (command_spans, rest_spans) = spans.split_at(split_id); let (command_spans, rest_spans) = spans.split_at(split_id);
@ -2099,7 +2096,7 @@ pub fn parse_module(
}; };
let module_decl_id = working_set let module_decl_id = working_set
.find_decl(b"module", &Type::Nothing) .find_decl(b"module")
.expect("internal error: missing module command"); .expect("internal error: missing module command");
let call = Box::new(Call { let call = Box::new(Call {
@ -2150,7 +2147,7 @@ pub fn parse_use(working_set: &mut StateWorkingSet, spans: &[Span]) -> (Pipeline
return (garbage_pipeline(spans), vec![]); return (garbage_pipeline(spans), vec![]);
} }
let (call, call_span, args_spans) = match working_set.find_decl(b"use", &Type::Nothing) { let (call, call_span, args_spans) = match working_set.find_decl(b"use") {
Some(decl_id) => { Some(decl_id) => {
let (command_spans, rest_spans) = spans.split_at(split_id); let (command_spans, rest_spans) = spans.split_at(split_id);
@ -2306,7 +2303,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
return garbage_pipeline(spans); return garbage_pipeline(spans);
} }
let (call, args_spans) = match working_set.find_decl(b"hide", &Type::Nothing) { let (call, args_spans) = match working_set.find_decl(b"hide") {
Some(decl_id) => { Some(decl_id) => {
let ParsedInternalCall { call, output } = let ParsedInternalCall { call, output } =
parse_internal_call(working_set, spans[0], &spans[1..], decl_id); parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
@ -2365,7 +2362,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
(true, working_set.get_module(module_id).clone()) (true, working_set.get_module(module_id).clone())
} else if import_pattern.members.is_empty() { } else if import_pattern.members.is_empty() {
// The pattern head can be: // The pattern head can be:
if let Some(id) = working_set.find_decl(&import_pattern.head.name, &Type::Nothing) { if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
// a custom command, // a custom command,
let mut module = Module::new(b"tmp".to_vec()); let mut module = Module::new(b"tmp".to_vec());
module.add_decl(import_pattern.head.name.clone(), id); module.add_decl(import_pattern.head.name.clone(), id);
@ -2803,7 +2800,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
// return Pipeline::from_vec(vec![garbage(*span)]); // return Pipeline::from_vec(vec![garbage(*span)]);
// } // }
if let Some(decl_id) = working_set.find_decl(b"let", &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(b"let") {
if spans.len() >= 4 { if spans.len() >= 4 {
// This is a bit of by-hand parsing to get around the issue where we want to parse in the reverse order // This is a bit of by-hand parsing to get around the issue where we want to parse in the reverse order
// so that the var-id created by the variable isn't visible in the expression that init it // so that the var-id created by the variable isn't visible in the expression that init it
@ -2919,7 +2916,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin
// return Pipeline::from_vec(vec![garbage(*span)]); // return Pipeline::from_vec(vec![garbage(*span)]);
// } // }
if let Some(decl_id) = working_set.find_decl(b"const", &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(b"const") {
let cmd = working_set.get_decl(decl_id); let cmd = working_set.get_decl(decl_id);
let call_signature = cmd.signature().call_signature(); let call_signature = cmd.signature().call_signature();
@ -3041,7 +3038,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
// return Pipeline::from_vec(vec![garbage(*span)]); // return Pipeline::from_vec(vec![garbage(*span)]);
// } // }
if let Some(decl_id) = working_set.find_decl(b"mut", &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(b"mut") {
if spans.len() >= 4 { if spans.len() >= 4 {
// This is a bit of by-hand parsing to get around the issue where we want to parse in the reverse order // This is a bit of by-hand parsing to get around the issue where we want to parse in the reverse order
// so that the var-id created by the variable isn't visible in the expression that init it // so that the var-id created by the variable isn't visible in the expression that init it
@ -3155,7 +3152,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeli
if name == b"source" || name == b"source-env" { if name == b"source" || name == b"source-env" {
let scoped = name == b"source-env"; let scoped = name == b"source-env";
if let Some(decl_id) = working_set.find_decl(name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(name) {
let cwd = working_set.get_cwd(); let cwd = working_set.get_cwd();
// Is this the right call to be using here? // Is this the right call to be using here?
@ -3286,7 +3283,7 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex
return garbage(span(spans)); return garbage(span(spans));
} }
let call = match working_set.find_decl(b"where", &Type::List(Box::new(Type::Any))) { let call = match working_set.find_decl(b"where") {
Some(decl_id) => { Some(decl_id) => {
let ParsedInternalCall { call, output } = let ParsedInternalCall { call, output } =
parse_internal_call(working_set, spans[0], &spans[1..], decl_id); parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
@ -3349,7 +3346,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipe
// Parsing the spans and checking that they match the register signature // Parsing the spans and checking that they match the register signature
// Using a parsed call makes more sense than checking for how many spans are in the call // Using a parsed call makes more sense than checking for how many spans are in the call
// Also, by creating a call, it can be checked if it matches the declaration signature // Also, by creating a call, it can be checked if it matches the declaration signature
let (call, call_span) = match working_set.find_decl(b"register", &Type::Nothing) { let (call, call_span) = match working_set.find_decl(b"register") {
None => { None => {
working_set.error(ParseError::UnknownState( working_set.error(ParseError::UnknownState(
"internal error: Register declaration not found".into(), "internal error: Register declaration not found".into(),

View File

@ -815,8 +815,6 @@ pub fn parse_internal_call(
} }
} }
working_set.type_scope.add_type(output.clone());
if signature.creates_scope { if signature.creates_scope {
working_set.enter_scope(); working_set.enter_scope();
} }
@ -1052,8 +1050,7 @@ pub fn parse_call(
pos += 1; pos += 1;
} }
let input = working_set.type_scope.get_previous(); let mut maybe_decl_id = working_set.find_decl(&name);
let mut maybe_decl_id = working_set.find_decl(&name, input);
while maybe_decl_id.is_none() { while maybe_decl_id.is_none() {
// Find the longest command match // Find the longest command match
@ -1075,7 +1072,7 @@ pub fn parse_call(
name.extend(name_part); name.extend(name_part);
} }
} }
maybe_decl_id = working_set.find_decl(&name, input); maybe_decl_id = working_set.find_decl(&name);
} }
if let Some(decl_id) = maybe_decl_id { if let Some(decl_id) = maybe_decl_id {
@ -1096,7 +1093,7 @@ pub fn parse_call(
} }
// TODO: Try to remove the clone // TODO: Try to remove the clone
let decl = working_set.get_decl(decl_id).clone(); let decl = working_set.get_decl(decl_id);
let parsed_call = if let Some(alias) = decl.as_alias() { let parsed_call = if let Some(alias) = decl.as_alias() {
if let Expression { if let Expression {
@ -1104,7 +1101,7 @@ pub fn parse_call(
span: _, span: _,
ty, ty,
custom_completion, custom_completion,
} = &alias.wrapped_call } = &alias.clone().wrapped_call
{ {
trace!("parsing: alias of external call"); trace!("parsing: alias of external call");
@ -2004,9 +2001,6 @@ pub fn parse_full_cell_path(
// Creating a Type scope to parse the new block. This will keep track of // Creating a Type scope to parse the new block. This will keep track of
// the previous input type found in that block // the previous input type found in that block
let output = parse_block(working_set, &output, span, true, true); let output = parse_block(working_set, &output, span, true, true);
working_set
.type_scope
.add_type(working_set.type_scope.get_last_output());
let ty = output.output_type(); let ty = output.output_type();
@ -2742,7 +2736,7 @@ pub fn parse_shape_name(
return SyntaxShape::Any; return SyntaxShape::Any;
} }
let decl_id = working_set.find_decl(command_name, &Type::Any); let decl_id = working_set.find_decl(command_name);
if let Some(decl_id) = decl_id { if let Some(decl_id) = decl_id {
return SyntaxShape::Custom(Box::new(shape), decl_id); return SyntaxShape::Custom(Box::new(shape), decl_id);
@ -5088,7 +5082,7 @@ pub fn parse_expression(
} }
}; };
let with_env = working_set.find_decl(b"with-env", &Type::Any); let with_env = working_set.find_decl(b"with-env");
if !shorthand.is_empty() { if !shorthand.is_empty() {
if let Some(decl_id) = with_env { if let Some(decl_id) = with_env {
@ -5146,14 +5140,7 @@ pub fn parse_variable(working_set: &mut StateWorkingSet, span: Span) -> Option<V
let bytes = working_set.get_span_contents(span); let bytes = working_set.get_span_contents(span);
if is_variable(bytes) { if is_variable(bytes) {
if let Some(var_id) = working_set.find_variable(bytes) { working_set.find_variable(bytes)
let input = working_set.get_variable(var_id).ty.clone();
working_set.type_scope.add_type(input);
Some(var_id)
} else {
None
}
} else { } else {
working_set.error(ParseError::Expected("valid variable name", span)); working_set.error(ParseError::Expected("valid variable name", span));
@ -5172,7 +5159,7 @@ pub fn parse_builtin_commands(
{ {
trace!("parsing: not math expression or unaliasable parser keyword"); trace!("parsing: not math expression or unaliasable parser keyword");
let name = working_set.get_span_contents(lite_command.parts[0]); let name = working_set.get_span_contents(lite_command.parts[0]);
if let Some(decl_id) = working_set.find_decl(name, &Type::Nothing) { if let Some(decl_id) = working_set.find_decl(name) {
let cmd = working_set.get_decl(decl_id); let cmd = working_set.get_decl(decl_id);
if cmd.is_alias() { if cmd.is_alias() {
// Parse keywords that can be aliased. Note that we check for "unaliasable" keywords // Parse keywords that can be aliased. Note that we check for "unaliasable" keywords
@ -5350,8 +5337,8 @@ pub fn parse_pipeline(
parse_builtin_commands(working_set, &new_command, is_subexpression); parse_builtin_commands(working_set, &new_command, is_subexpression);
if pipeline_index == 0 { if pipeline_index == 0 {
let let_decl_id = working_set.find_decl(b"let", &Type::Nothing); let let_decl_id = working_set.find_decl(b"let");
let mut_decl_id = working_set.find_decl(b"mut", &Type::Nothing); let mut_decl_id = working_set.find_decl(b"mut");
for element in pipeline.elements.iter_mut() { for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression( if let PipelineElement::Expression(
_, _,
@ -5416,7 +5403,6 @@ pub fn parse_pipeline(
LiteElement::Command(span, command) => { LiteElement::Command(span, command) => {
trace!("parsing: pipeline element: command"); trace!("parsing: pipeline element: command");
let expr = parse_expression(working_set, &command.parts, is_subexpression); let expr = parse_expression(working_set, &command.parts, is_subexpression);
working_set.type_scope.add_type(expr.ty.clone());
PipelineElement::Expression(*span, expr) PipelineElement::Expression(*span, expr)
} }
@ -5424,8 +5410,6 @@ pub fn parse_pipeline(
trace!("parsing: pipeline element: redirection"); trace!("parsing: pipeline element: redirection");
let expr = parse_string(working_set, command.parts[0]); let expr = parse_string(working_set, command.parts[0]);
working_set.type_scope.add_type(expr.ty.clone());
PipelineElement::Redirection(*span, redirection.clone(), expr) PipelineElement::Redirection(*span, redirection.clone(), expr)
} }
LiteElement::SeparateRedirection { LiteElement::SeparateRedirection {
@ -5435,12 +5419,8 @@ pub fn parse_pipeline(
trace!("parsing: pipeline element: separate redirection"); trace!("parsing: pipeline element: separate redirection");
let out_expr = parse_string(working_set, out_command.parts[0]); let out_expr = parse_string(working_set, out_command.parts[0]);
working_set.type_scope.add_type(out_expr.ty.clone());
let err_expr = parse_string(working_set, err_command.parts[0]); let err_expr = parse_string(working_set, err_command.parts[0]);
working_set.type_scope.add_type(err_expr.ty.clone());
PipelineElement::SeparateRedirection { PipelineElement::SeparateRedirection {
out: (*out_span, out_expr), out: (*out_span, out_expr),
err: (*err_span, err_expr), err: (*err_span, err_expr),
@ -5452,9 +5432,7 @@ pub fn parse_pipeline(
} => { } => {
trace!("parsing: pipeline element: same target redirection"); trace!("parsing: pipeline element: same target redirection");
let expr = parse_expression(working_set, &command.parts, is_subexpression); let expr = parse_expression(working_set, &command.parts, is_subexpression);
working_set.type_scope.add_type(expr.ty.clone());
let redirect_expr = parse_string(working_set, redirect_command.parts[0]); let redirect_expr = parse_string(working_set, redirect_command.parts[0]);
working_set.type_scope.add_type(redirect_expr.ty.clone());
PipelineElement::SameTargetRedirection { PipelineElement::SameTargetRedirection {
cmd: (*cmd_span, expr), cmd: (*cmd_span, expr),
redirection: (*redirect_span, redirect_expr), redirection: (*redirect_span, redirect_expr),
@ -5487,8 +5465,8 @@ pub fn parse_pipeline(
} => { } => {
let mut pipeline = parse_builtin_commands(working_set, command, is_subexpression); let mut pipeline = parse_builtin_commands(working_set, command, is_subexpression);
let let_decl_id = working_set.find_decl(b"let", &Type::Nothing); let let_decl_id = working_set.find_decl(b"let");
let mut_decl_id = working_set.find_decl(b"mut", &Type::Nothing); let mut_decl_id = working_set.find_decl(b"mut");
if pipeline_index == 0 { if pipeline_index == 0 {
for element in pipeline.elements.iter_mut() { for element in pipeline.elements.iter_mut() {
@ -5542,12 +5520,9 @@ pub fn parse_pipeline(
} => { } => {
trace!("parsing: pipeline element: same target redirection"); trace!("parsing: pipeline element: same target redirection");
let expr = parse_expression(working_set, &command.parts, is_subexpression); let expr = parse_expression(working_set, &command.parts, is_subexpression);
working_set.type_scope.add_type(expr.ty.clone());
let redirect_expr = parse_string(working_set, redirect_cmd.parts[0]); let redirect_expr = parse_string(working_set, redirect_cmd.parts[0]);
working_set.type_scope.add_type(redirect_expr.ty.clone());
Pipeline { Pipeline {
elements: vec![PipelineElement::SameTargetRedirection { elements: vec![PipelineElement::SameTargetRedirection {
cmd: (*span, expr), cmd: (*span, expr),
@ -5576,7 +5551,6 @@ pub fn parse_block(
if scoped { if scoped {
working_set.enter_scope(); working_set.enter_scope();
} }
working_set.type_scope.enter_scope();
// Pre-declare any definition so that definitions // Pre-declare any definition so that definitions
// that share the same block can see each other // that share the same block can see each other
@ -5605,7 +5579,6 @@ pub fn parse_block(
if scoped { if scoped {
working_set.exit_scope(); working_set.exit_scope();
} }
working_set.type_scope.exit_scope();
block.span = Some(span); block.span = Some(span);
@ -6008,7 +5981,7 @@ fn wrap_element_with_collect(
fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression { fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) -> Expression {
let span = expr.span; let span = expr.span;
if let Some(decl_id) = working_set.find_decl(b"collect", &Type::List(Box::new(Type::Any))) { if let Some(decl_id) = working_set.find_decl(b"collect") {
let mut output = vec![]; let mut output = vec![];
let var_id = IN_VARIABLE_ID; let var_id = IN_VARIABLE_ID;

View File

@ -1590,177 +1590,6 @@ mod input_types {
.expect("Error merging delta"); .expect("Error merging delta");
} }
#[test]
fn call_types_test() {
let mut engine_state = EngineState::new();
add_declarations(&mut engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
let input = r#"ls | to-custom | group-by name other"#;
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(working_set.parse_errors.is_empty());
assert_eq!(block.len(), 1);
let expressions = &block[0];
assert_eq!(expressions.len(), 3);
match &expressions[0] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"ls", &Type::Nothing)
.expect("Error merging delta");
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
match &expressions[1] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
match &expressions[2] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"group-by", &Type::Custom("custom".into()))
.unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
}
#[test]
fn storing_variable_test() {
let mut engine_state = EngineState::new();
add_declarations(&mut engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
let input =
r#"let a = (ls | to-custom | group-by name other); let b = (1+3); $a | agg sum"#;
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(working_set.parse_errors.is_empty());
assert_eq!(block.len(), 3);
let expressions = &block[2];
match &expressions[1] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"agg", &Type::Custom("custom".into()))
.unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
}
#[test]
fn stored_variable_operation_test() {
let mut engine_state = EngineState::new();
add_declarations(&mut engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
let input = r#"let a = (ls | to-custom | group-by name other); ($a + $a) | agg sum"#;
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(working_set.parse_errors.is_empty());
assert_eq!(block.len(), 2);
let expressions = &block[1];
match &expressions[1] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set
.find_decl(b"agg", &Type::Custom("custom".into()))
.unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
}
#[test]
fn multiple_stored_variable_test() {
let mut engine_state = EngineState::new();
add_declarations(&mut engine_state);
let mut working_set = StateWorkingSet::new(&engine_state);
let input = r#"
let a = (ls | to-custom | group-by name other); [1 2 3] | to-custom; [1 2 3] | to-custom"#;
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(working_set.parse_errors.is_empty());
assert_eq!(block.len(), 3);
let expressions = &block[1];
match &expressions[1] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
let expressions = &block[2];
match &expressions[1] {
PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) => {
let expected_id = working_set.find_decl(b"to-custom", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id)
}
_ => panic!("Expected expression Call not found"),
}
}
#[test] #[test]
fn call_non_custom_types_test() { fn call_non_custom_types_test() {
let mut engine_state = EngineState::new(); let mut engine_state = EngineState::new();
@ -1785,7 +1614,7 @@ mod input_types {
.. ..
}, },
) => { ) => {
let expected_id = working_set.find_decl(b"ls", &Type::Nothing).unwrap(); let expected_id = working_set.find_decl(b"ls").unwrap();
assert_eq!(call.decl_id, expected_id) assert_eq!(call.decl_id, expected_id)
} }
_ => panic!("Expected expression Call not found"), _ => panic!("Expected expression Call not found"),
@ -1799,7 +1628,7 @@ mod input_types {
.. ..
}, },
) => { ) => {
let expected_id = working_set.find_decl(b"group-by", &Type::Any).unwrap(); let expected_id = working_set.find_decl(b"group-by").unwrap();
assert_eq!(call.decl_id, expected_id) assert_eq!(call.decl_id, expected_id)
} }
_ => panic!("Expected expression Call not found"), _ => panic!("Expected expression Call not found"),
@ -1849,8 +1678,7 @@ mod input_types {
}, },
) => { ) => {
let working_set = StateWorkingSet::new(&engine_state); let working_set = StateWorkingSet::new(&engine_state);
let expected_id = let expected_id = working_set.find_decl(b"min").unwrap();
working_set.find_decl(b"min", &Type::Any).unwrap();
assert_eq!(call.decl_id, expected_id) assert_eq!(call.decl_id, expected_id)
} }
_ => panic!("Expected expression Call not found"), _ => panic!("Expected expression Call not found"),
@ -1889,9 +1717,7 @@ mod input_types {
.. ..
}, },
) => { ) => {
let expected_id = working_set let expected_id = working_set.find_decl(b"with-column").unwrap();
.find_decl(b"with-column", &Type::Custom("custom".into()))
.unwrap();
assert_eq!(call.decl_id, expected_id) assert_eq!(call.decl_id, expected_id)
} }
_ => panic!("Expected expression Call not found"), _ => panic!("Expected expression Call not found"),
@ -1905,9 +1731,7 @@ mod input_types {
.. ..
}, },
) => { ) => {
let expected_id = working_set let expected_id = working_set.find_decl(b"collect").unwrap();
.find_decl(b"collect", &Type::Custom("custom".into()))
.unwrap();
assert_eq!(call.decl_id, expected_id) assert_eq!(call.decl_id, expected_id)
} }
_ => panic!("Expected expression Call not found"), _ => panic!("Expected expression Call not found"),

View File

@ -621,7 +621,7 @@ impl EngineState {
for overlay_frame in self.active_overlays(removed_overlays).rev() { for overlay_frame in self.active_overlays(removed_overlays).rev() {
visibility.append(&overlay_frame.visibility); visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) { if let Some(decl_id) = overlay_frame.get_decl(name) {
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id); return Some(decl_id);
} }
@ -638,7 +638,7 @@ impl EngineState {
visibility.append(&overlay_frame.visibility); visibility.append(&overlay_frame.visibility);
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
for ((name, _), id) in overlay_frame.decls.iter() { for (name, id) in overlay_frame.decls.iter() {
if id == &decl_id { if id == &decl_id {
return Some(name); return Some(name);
} }
@ -714,12 +714,12 @@ impl EngineState {
for overlay_frame in self.active_overlays(&[]).rev() { for overlay_frame in self.active_overlays(&[]).rev() {
for decl in &overlay_frame.decls { for decl in &overlay_frame.decls {
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0) { if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
let command = self.get_decl(*decl.1); let command = self.get_decl(*decl.1);
if ignore_deprecated && command.signature().category == Category::Deprecated { if ignore_deprecated && command.signature().category == Category::Deprecated {
continue; continue;
} }
output.push((decl.0 .0.clone(), Some(command.usage().to_string()))); output.push((decl.0.clone(), Some(command.usage().to_string())));
} }
} }
} }
@ -790,7 +790,7 @@ impl EngineState {
} }
let mut decls: Vec<(Vec<u8>, DeclId)> = let mut decls: Vec<(Vec<u8>, DeclId)> =
decls_map.into_iter().map(|(v, k)| (v.0, k)).collect(); decls_map.into_iter().map(|(v, k)| (v, k)).collect();
decls.sort_by(|a, b| a.0.cmp(&b.0)); decls.sort_by(|a, b| a.0.cmp(&b.0));
decls.into_iter() decls.into_iter()
@ -953,7 +953,6 @@ pub struct StateWorkingSet<'a> {
pub permanent_state: &'a EngineState, pub permanent_state: &'a EngineState,
pub delta: StateDelta, pub delta: StateDelta,
pub external_commands: Vec<Vec<u8>>, pub external_commands: Vec<Vec<u8>>,
pub type_scope: TypeScope,
/// Current working directory relative to the file being parsed right now /// Current working directory relative to the file being parsed right now
pub currently_parsed_cwd: Option<PathBuf>, pub currently_parsed_cwd: Option<PathBuf>,
/// All previously parsed module files. Used to protect against circular imports. /// All previously parsed module files. Used to protect against circular imports.
@ -963,54 +962,6 @@ pub struct StateWorkingSet<'a> {
pub parse_errors: Vec<ParseError>, pub parse_errors: Vec<ParseError>,
} }
/// A temporary placeholder for expression types. It is used to keep track of the input types
/// for each expression in a pipeline
pub struct TypeScope {
/// Layers that map the type inputs that are found in each parsed block
outputs: Vec<Vec<Type>>,
/// The last know output from a parsed block
last_output: Type,
}
impl Default for TypeScope {
fn default() -> Self {
Self {
outputs: Vec::new(),
last_output: Type::Any,
}
}
}
impl TypeScope {
pub fn get_previous(&self) -> &Type {
match self.outputs.last().and_then(|v| v.last()) {
Some(input) => input,
None => &Type::Nothing,
}
}
pub fn get_last_output(&self) -> Type {
self.last_output.clone()
}
pub fn add_type(&mut self, input: Type) {
if let Some(v) = self.outputs.last_mut() {
v.push(input)
} else {
self.outputs.push(vec![input])
}
}
pub fn enter_scope(&mut self) {
self.outputs.push(Vec::new())
}
pub fn exit_scope(&mut self) -> Option<Vec<Type>> {
self.last_output = self.get_previous().clone();
self.outputs.pop()
}
}
/// A delta (or change set) between the current global state and a possible future global state. Deltas /// A delta (or change set) between the current global state and a possible future global state. Deltas
/// can be applied to the global state to update it to contain both previous state and the state held /// can be applied to the global state to update it to contain both previous state and the state held
/// within the delta. /// within the delta.
@ -1141,7 +1092,6 @@ impl<'a> StateWorkingSet<'a> {
delta: StateDelta::new(permanent_state), delta: StateDelta::new(permanent_state),
permanent_state, permanent_state,
external_commands: vec![], external_commands: vec![],
type_scope: TypeScope::default(),
currently_parsed_cwd: permanent_state.currently_parsed_cwd.clone(), currently_parsed_cwd: permanent_state.currently_parsed_cwd.clone(),
parsed_module_files: vec![], parsed_module_files: vec![],
search_predecls: true, search_predecls: true,
@ -1197,13 +1147,11 @@ impl<'a> StateWorkingSet<'a> {
pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId { pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId {
let name = decl.name().as_bytes().to_vec(); let name = decl.name().as_bytes().to_vec();
let input_type = decl.signature().get_input_type();
self.delta.decls.push(decl); self.delta.decls.push(decl);
let decl_id = self.num_decls() - 1; let decl_id = self.num_decls() - 1;
self.last_overlay_mut() self.last_overlay_mut().insert_decl(name, decl_id);
.insert_decl(name, input_type, decl_id);
decl_id decl_id
} }
@ -1212,7 +1160,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = self.last_overlay_mut(); let overlay_frame = self.last_overlay_mut();
for (name, decl_id) in decls { for (name, decl_id) in decls {
overlay_frame.insert_decl(name, Type::Any, decl_id); overlay_frame.insert_decl(name, decl_id);
overlay_frame.visibility.use_decl_id(&decl_id); overlay_frame.visibility.use_decl_id(&decl_id);
} }
} }
@ -1249,7 +1197,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = self.last_overlay_mut(); let overlay_frame = self.last_overlay_mut();
if let Some(decl_id) = overlay_frame.predecls.remove(name) { if let Some(decl_id) = overlay_frame.predecls.remove(name) {
overlay_frame.insert_decl(name.into(), Type::Any, decl_id); overlay_frame.insert_decl(name.into(), decl_id);
return Some(decl_id); return Some(decl_id);
} }
@ -1279,7 +1227,7 @@ impl<'a> StateWorkingSet<'a> {
visibility.append(&overlay_frame.visibility); visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) { if let Some(decl_id) = overlay_frame.get_decl(name) {
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
// Hide decl only if it's not already hidden // Hide decl only if it's not already hidden
overlay_frame.visibility.hide_decl_id(&decl_id); overlay_frame.visibility.hide_decl_id(&decl_id);
@ -1298,7 +1246,7 @@ impl<'a> StateWorkingSet<'a> {
{ {
visibility.append(&overlay_frame.visibility); visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.get_decl(name, &Type::Any) { if let Some(decl_id) = overlay_frame.get_decl(name) {
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
// Hide decl only if it's not already hidden // Hide decl only if it's not already hidden
self.last_overlay_mut().visibility.hide_decl_id(&decl_id); self.last_overlay_mut().visibility.hide_decl_id(&decl_id);
@ -1467,7 +1415,7 @@ impl<'a> StateWorkingSet<'a> {
None None
} }
pub fn find_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> { pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
let mut removed_overlays = vec![]; let mut removed_overlays = vec![];
let mut visibility: Visibility = Visibility::new(); let mut visibility: Visibility = Visibility::new();
@ -1493,7 +1441,7 @@ impl<'a> StateWorkingSet<'a> {
} }
} }
if let Some(decl_id) = overlay_frame.get_decl(name, input) { if let Some(decl_id) = overlay_frame.get_decl(name) {
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id); return Some(decl_id);
} }
@ -1509,7 +1457,7 @@ impl<'a> StateWorkingSet<'a> {
{ {
visibility.append(&overlay_frame.visibility); visibility.append(&overlay_frame.visibility);
if let Some(decl_id) = overlay_frame.get_decl(name, input) { if let Some(decl_id) = overlay_frame.get_decl(name) {
if visibility.is_decl_id_visible(&decl_id) { if visibility.is_decl_id_visible(&decl_id) {
return Some(decl_id); return Some(decl_id);
} }
@ -1549,7 +1497,7 @@ impl<'a> StateWorkingSet<'a> {
for scope_frame in self.delta.scope.iter().rev() { for scope_frame in self.delta.scope.iter().rev() {
for overlay_frame in scope_frame.active_overlays(&mut removed_overlays).rev() { for overlay_frame in scope_frame.active_overlays(&mut removed_overlays).rev() {
for decl in &overlay_frame.decls { for decl in &overlay_frame.decls {
if decl.0 .0.starts_with(name) { if decl.0.starts_with(name) {
return true; return true;
} }
} }
@ -1562,7 +1510,7 @@ impl<'a> StateWorkingSet<'a> {
.rev() .rev()
{ {
for decl in &overlay_frame.decls { for decl in &overlay_frame.decls {
if decl.0 .0.starts_with(name) { if decl.0.starts_with(name) {
return true; return true;
} }
} }
@ -1768,14 +1716,13 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = scope_frame.get_overlay(*overlay_id); let overlay_frame = scope_frame.get_overlay(*overlay_id);
for decl in &overlay_frame.decls { for decl in &overlay_frame.decls {
if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(&decl.0 .0) if overlay_frame.visibility.is_decl_id_visible(decl.1) && predicate(decl.0) {
{
let command = self.get_decl(*decl.1); let command = self.get_decl(*decl.1);
if ignore_deprecated && command.signature().category == Category::Deprecated if ignore_deprecated && command.signature().category == Category::Deprecated
{ {
continue; continue;
} }
output.push((decl.0 .0.clone(), Some(command.usage().to_string()))); output.push((decl.0.clone(), Some(command.usage().to_string())));
} }
} }
} }
@ -1908,7 +1855,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = self.permanent_state.get_overlay(overlay_id); let overlay_frame = self.permanent_state.get_overlay(overlay_id);
for (decl_key, decl_id) in &overlay_frame.decls { for (decl_key, decl_id) in &overlay_frame.decls {
result.insert(decl_key.0.to_owned(), *decl_id); result.insert(decl_key.to_owned(), *decl_id);
} }
} }
@ -1917,7 +1864,7 @@ impl<'a> StateWorkingSet<'a> {
let overlay_frame = scope_frame.get_overlay(overlay_id); let overlay_frame = scope_frame.get_overlay(overlay_id);
for (decl_key, decl_id) in &overlay_frame.decls { for (decl_key, decl_id) in &overlay_frame.decls {
result.insert(decl_key.0.to_owned(), *decl_id); result.insert(decl_key.to_owned(), *decl_id);
} }
} }
} }

View File

@ -1,7 +1,5 @@
use crate::{DeclId, ModuleId, OverlayId, Type, Value, VarId}; use crate::{DeclId, ModuleId, OverlayId, Value, VarId};
use std::borrow::Borrow;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{Hash, Hasher};
pub static DEFAULT_OVERLAY_NAME: &str = "zero"; pub static DEFAULT_OVERLAY_NAME: &str = "zero";
@ -181,7 +179,7 @@ pub struct OverlayFrame {
pub vars: HashMap<Vec<u8>, VarId>, pub vars: HashMap<Vec<u8>, VarId>,
pub constants: HashMap<VarId, Value>, pub constants: HashMap<VarId, Value>,
pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
pub decls: HashMap<(Vec<u8>, Type), DeclId>, pub decls: HashMap<Vec<u8>, DeclId>,
pub modules: HashMap<Vec<u8>, ModuleId>, pub modules: HashMap<Vec<u8>, ModuleId>,
pub visibility: Visibility, pub visibility: Visibility,
pub origin: ModuleId, // The original module the overlay was created from pub origin: ModuleId, // The original module the overlay was created from
@ -202,82 +200,16 @@ impl OverlayFrame {
} }
} }
pub fn insert_decl(&mut self, name: Vec<u8>, input: Type, decl_id: DeclId) -> Option<DeclId> { pub fn insert_decl(&mut self, name: Vec<u8>, decl_id: DeclId) -> Option<DeclId> {
self.decls.insert((name, input), decl_id) self.decls.insert(name, decl_id)
} }
pub fn insert_module(&mut self, name: Vec<u8>, module_id: ModuleId) -> Option<ModuleId> { pub fn insert_module(&mut self, name: Vec<u8>, module_id: ModuleId) -> Option<ModuleId> {
self.modules.insert(name, module_id) self.modules.insert(name, module_id)
} }
pub fn get_decl(&self, name: &[u8], input: &Type) -> Option<DeclId> { pub fn get_decl(&self, name: &[u8]) -> Option<DeclId> {
if let Some(decl) = self.decls.get(&(name, input) as &dyn DeclKey) { self.decls.get(name).cloned()
Some(*decl)
} else {
// then fallback to not using the input type
for decl_key in self.decls.keys() {
if decl_key.0 == name {
// FIXME: this fallback may give bad type information
// in the case where no matching type is found. But, at
// least we treat it as a found internal command rather
// than an external command, which would cause further issues
return Some(
*self
.decls
.get(decl_key)
.expect("internal error: found decl not actually found"),
);
}
}
None
}
}
}
trait DeclKey {
fn name(&self) -> &[u8];
fn input(&self) -> &Type;
}
impl Hash for dyn DeclKey + '_ {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
self.input().hash(state);
}
}
impl PartialEq for dyn DeclKey + '_ {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name() && self.input() == other.input()
}
}
impl Eq for dyn DeclKey + '_ {}
impl<'a> DeclKey for (&'a [u8], &Type) {
fn name(&self) -> &[u8] {
self.0
}
fn input(&self) -> &Type {
self.1
}
}
impl DeclKey for (Vec<u8>, Type) {
fn name(&self) -> &[u8] {
&self.0
}
fn input(&self) -> &Type {
&self.1
}
}
impl<'a> Borrow<dyn DeclKey + 'a> for (Vec<u8>, Type) {
fn borrow(&self) -> &(dyn DeclKey + 'a) {
self
} }
} }