diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b1ee3378bb2532a62adcfc09203911ae2f67364d..4fcfec382b711e8a7f52db3646521a31512311a0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,7 +17,7 @@ format:
     - cargo +nightly fmt --all -- --check
 
 linux:
-  image: 'rust:1.31.0'
+  image: 'rust:1.32.0'
   script:
     - cargo build
     - make tests
diff --git a/Makefile b/Makefile
index 699f3dd2af043684054f97df0863204d5581cf26..0c6bc685146b7070dc8d5588536eadd238a5d342 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 prefix ?= usr/local
 BINARY = $(prefix)/bin/ion
 RELEASE = debug
-TOOLCHAIN ?= 1.31.0
+TOOLCHAIN ?= 1.32.0
 
 GIT_REVISION=git_revision.txt
 SRC=Cargo.toml Cargo.lock $(shell find src members -type f -wholename '*src/*.rs')
diff --git a/README.md b/README.md
index db7b1b5b13a8258f97d260ddf0ba010430b9e00b..d4146e89c872c46f63ec49d83cd63cee67ca22dc 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ with **mdbook**.
 
 ## Pop!\_OS / Ubuntu
 
-The following PPA supports the 18.04 (bionic) and 18.10 (cosmic) releases. Bionic builds were made using the Pop\_OS PPA's rustc 1.31.0 package.
+The following PPA supports the 18.04 (bionic) and 18.10 (cosmic) releases. Bionic builds were made using the Pop\_OS PPA's rustc 1.32.0 package.
 
 ```
 sudo add-apt-repository ppa:mmstick76/ion-shell
@@ -41,13 +41,13 @@ sudo add-apt-repository ppa:mmstick76/ion-shell
 # Developer set up
 
 Those who are developing software with Rust should install the [Rustup toolchain manager](https://rustup.rs/).
-After installing rustup, run `rustup override set 1.31.0` to set your Rust toolchain to the version that Ion is
+After installing rustup, run `rustup override set 1.32.0` to set your Rust toolchain to the version that Ion is
 targeting at the moment. To build for Redox OS, `rustup override set nightly` is required to build the Redox
 dependencies.
 
 # Build dependencies
 
-Please ensure that both cargo and rustc 1.31.0 or higher is installed for your system.
+Please ensure that both cargo and rustc 1.32.0 or higher is installed for your system.
 Release tarballs have not been made yet due to Ion being incomplete in a few remaining areas.
 
 # Compile instructions for distribution
diff --git a/benches/statement.rs b/benches/statement.rs
index a5109b8d30613ce9c37cde1d70f953f18a8e6019..40593e2f83d829fbad8f58a242b2c9faed3f06a0 100644
--- a/benches/statement.rs
+++ b/benches/statement.rs
@@ -1,5 +1,5 @@
 use criterion::*;
-use ion_shell::parser::{statement::StatementSplitter, Terminator};
+use ion_shell::parser::{StatementSplitter, Terminator};
 use itertools::Itertools;
 
 const TEXT: &[u8] = include_bytes!("test.ion");
diff --git a/members/braces/src/lib.rs b/members/braces/src/lib.rs
index 5f6a8827ea6eba1554c553f49da231c87305910d..9beb87974417f3781934a53e3658d535c118dced 100644
--- a/members/braces/src/lib.rs
+++ b/members/braces/src/lib.rs
@@ -106,7 +106,7 @@ where
                     &mut small_vec,
                     match *token {
                         BraceToken::Normal(ref text) => text,
-                        BraceToken::Expander => element.as_ref(),
+                        BraceToken::Expander => element,
                     },
                 );
                 small_vec
diff --git a/src/binary/completer.rs b/src/binary/completer.rs
index a8f323e3344b6f4da740281944750a4fafcc2b0b..3537be41c1ff5eb91d247fb497df7f28663bfa11 100644
--- a/src/binary/completer.rs
+++ b/src/binary/completer.rs
@@ -4,6 +4,7 @@ use ion_shell::{
     parser::{unescape, Expander},
     Shell,
 };
+use ion_sys::PATH_SEPARATOR;
 use liner::{BasicCompleter, Completer, CursorPosition, Event, EventKind};
 use smallvec::SmallVec;
 use std::{env, iter, path::PathBuf, str};
@@ -69,7 +70,7 @@ impl<'a, 'b> Completer for IonCompleter<'a, 'b> {
             // in the environment's **$PATH** variable.
             let file_completers: Vec<_> = env::var("PATH")
                 .unwrap_or_else(|_| "/bin/".to_string())
-                .split(sys::PATH_SEPARATOR)
+                .split(PATH_SEPARATOR)
                 .map(|s| IonFileCompleter::new(Some(s), &self.shell))
                 .collect();
             // Merge the collected definitions with the file path definitions.
@@ -78,7 +79,7 @@ impl<'a, 'b> Completer for IonCompleter<'a, 'b> {
         completions
     }
 
-    fn on_event<W: std::io::Write>(&mut self, event: Event<W>) {
+    fn on_event<W: std::io::Write>(&mut self, event: Event<'_, '_, W>) {
         if let EventKind::BeforeComplete = event.kind {
             let (words, pos) = event.editor.get_words_and_cursor_position();
 
diff --git a/src/binary/mod.rs b/src/binary/mod.rs
index 9a69d2b94db845b2e530e26ceb2bcf95f39a5a20..575ae93a07cf0426cde8ce55834a664e58a80d05 100644
--- a/src/binary/mod.rs
+++ b/src/binary/mod.rs
@@ -12,6 +12,7 @@ use ion_shell::{
     status::Status,
     Shell,
 };
+use ion_sys::SIGHUP;
 use itertools::Itertools;
 use liner::{Buffer, Context, KeyBindings};
 use std::{cell::RefCell, path::Path, rc::Rc};
@@ -86,7 +87,7 @@ impl<'a> InteractiveBinary<'a> {
             // and waiting for the history thread in the background to finish.
             if shell.opts().huponexit {
                 shell.resume_stopped();
-                shell.background_send(sys::SIGHUP);
+                shell.background_send(SIGHUP);
             }
             context.borrow_mut().history.commit_to_file();
         })));
@@ -114,7 +115,7 @@ impl<'a> InteractiveBinary<'a> {
     /// Liner.
     pub fn execute_interactive(self) -> ! {
         let context_bis = self.context.clone();
-        let history = &move |args: &[small::String], _shell: &mut Shell| -> Status {
+        let history = &move |args: &[small::String], _shell: &mut Shell<'_>| -> Status {
             if man_pages::check_help(args, MAN_HISTORY) {
                 return Status::SUCCESS;
             }
@@ -124,7 +125,7 @@ impl<'a> InteractiveBinary<'a> {
         };
 
         let context_bis = self.context.clone();
-        let keybindings = &move |args: &[small::String], _shell: &mut Shell| -> Status {
+        let keybindings = &move |args: &[small::String], _shell: &mut Shell<'_>| -> Status {
             match args.get(1).map(|s| s.as_str()) {
                 Some("vi") => {
                     context_bis.borrow_mut().key_bindings = KeyBindings::Vi;
diff --git a/src/binary/prompt.rs b/src/binary/prompt.rs
index df03a2573ece49c6b5a6ec1f9f8079e034cd2754..d2a9f9c6f682a9981c78b4416c332cc9e6261622 100644
--- a/src/binary/prompt.rs
+++ b/src/binary/prompt.rs
@@ -1,7 +1,7 @@
 use ion_shell::{parser::Expander, Capture, Shell};
 use std::io::Read;
 
-pub fn prompt(shell: &Shell) -> String {
+pub fn prompt(shell: &Shell<'_>) -> String {
     let blocks = shell.block_len() + if shell.unterminated { 1 } else { 0 };
 
     if blocks == 0 {
@@ -16,7 +16,7 @@ pub fn prompt(shell: &Shell) -> String {
     }
 }
 
-pub fn prompt_fn(shell: &Shell) -> Option<String> {
+pub fn prompt_fn(shell: &Shell<'_>) -> Option<String> {
     shell
         .fork_function(
             Capture::StdoutThenIgnoreStderr,
diff --git a/src/binary/readln.rs b/src/binary/readln.rs
index 410532f5c62ce5ca67938b3b2351cd9adab1bf4b..a2e099b86117daaff14d02bb207e999a849e26dc 100644
--- a/src/binary/readln.rs
+++ b/src/binary/readln.rs
@@ -1,7 +1,7 @@
 use super::{completer::IonCompleter, InteractiveBinary};
 use std::io::ErrorKind;
 
-pub fn readln(binary: &InteractiveBinary) -> Option<String> {
+pub fn readln(binary: &InteractiveBinary<'_>) -> Option<String> {
     let prompt = binary.prompt();
     let line = binary.context.borrow_mut().read_line(
         prompt,
diff --git a/src/lib/builtins/command_info.rs b/src/lib/builtins/command_info.rs
index 204ef8656c2ab83857404f825aab51e006e3745c..70b61417a8579d8c9ec6d975935b705aede919a8 100644
--- a/src/lib/builtins/command_info.rs
+++ b/src/lib/builtins/command_info.rs
@@ -7,7 +7,7 @@ use small;
 
 use std::{borrow::Cow, env, path::Path};
 
-pub fn which(args: &[small::String], shell: &mut Shell) -> Result<Status, ()> {
+pub fn which(args: &[small::String], shell: &mut Shell<'_>) -> Result<Status, ()> {
     if check_help(args, MAN_WHICH) {
         return Ok(Status::SUCCESS);
     }
@@ -36,7 +36,7 @@ pub fn which(args: &[small::String], shell: &mut Shell) -> Result<Status, ()> {
     Ok(result)
 }
 
-pub fn find_type(args: &[small::String], shell: &mut Shell) -> Result<Status, ()> {
+pub fn find_type(args: &[small::String], shell: &mut Shell<'_>) -> Result<Status, ()> {
     // Type does not accept help flags, aka "--help".
     if args.len() == 1 {
         eprintln!("type: Expected at least 1 args, got only 0");
@@ -65,7 +65,7 @@ pub fn find_type(args: &[small::String], shell: &mut Shell) -> Result<Status, ()
     Ok(result)
 }
 
-fn get_command_info<'a>(command: &str, shell: &mut Shell) -> Result<Cow<'a, str>, ()> {
+fn get_command_info<'a>(command: &str, shell: &mut Shell<'_>) -> Result<Cow<'a, str>, ()> {
     match shell.variables().get_ref(command) {
         Some(Value::Alias(_)) => Ok("alias".into()),
         Some(Value::Function(_)) => Ok("function".into()),
diff --git a/src/lib/builtins/exec.rs b/src/lib/builtins/exec.rs
index 4837dcde68ae966200d160584c99d306e8595b10..b748cb8655dbc955a8c63f94a373a893a8bf1a41 100644
--- a/src/lib/builtins/exec.rs
+++ b/src/lib/builtins/exec.rs
@@ -7,7 +7,7 @@ use small;
 use std::error::Error;
 
 /// Executes the givent commmand.
-pub fn exec(shell: &mut Shell, args: &[small::String]) -> Result<(), small::String> {
+pub fn exec(shell: &mut Shell<'_>, args: &[small::String]) -> Result<(), small::String> {
     let mut clear_env = false;
     let mut idx = 0;
     for arg in args.iter() {
diff --git a/src/lib/builtins/exists.rs b/src/lib/builtins/exists.rs
index 265cda274b2b7920c4317256f2637b2a343b6875..f52b918239ced5b1bc13d3de597c040b53a89808 100644
--- a/src/lib/builtins/exists.rs
+++ b/src/lib/builtins/exists.rs
@@ -3,7 +3,7 @@ use std::{fs, os::unix::fs::PermissionsExt};
 use crate::shell::{Shell, Value};
 use small;
 
-pub fn exists(args: &[small::String], shell: &Shell) -> Result<bool, small::String> {
+pub fn exists(args: &[small::String], shell: &Shell<'_>) -> Result<bool, small::String> {
     match args.get(1) {
         Some(ref s) if s.starts_with("--") => {
             let (_, option) = s.split_at(2);
@@ -36,7 +36,7 @@ pub fn exists(args: &[small::String], shell: &Shell) -> Result<bool, small::Stri
 
 /// Matches flag arguments to their respective functionaity when the `-`
 /// character is detected.
-fn match_flag_argument(flag: char, argument: &str, shell: &Shell) -> bool {
+fn match_flag_argument(flag: char, argument: &str, shell: &Shell<'_>) -> bool {
     match flag {
         'a' => array_var_is_not_empty(argument, shell),
         'b' => binary_is_in_path(argument, shell),
@@ -48,7 +48,7 @@ fn match_flag_argument(flag: char, argument: &str, shell: &Shell) -> bool {
 }
 
 // Matches option arguments to their respective functionality
-fn match_option_argument(option: &str, argument: &str, shell: &Shell) -> bool {
+fn match_option_argument(option: &str, argument: &str, shell: &Shell<'_>) -> bool {
     match option {
         "fn" => function_is_defined(argument, &shell),
         _ => false,
@@ -66,7 +66,7 @@ fn path_is_directory(filepath: &str) -> bool {
 }
 
 /// Returns true if the binary is found in path (and is executable)
-fn binary_is_in_path(binaryname: &str, shell: &Shell) -> bool {
+fn binary_is_in_path(binaryname: &str, shell: &Shell<'_>) -> bool {
     // TODO: Maybe this function should reflect the logic for spawning new processes
     // TODO: Right now they use an entirely different logic which means that it
     // *might* be possible TODO: that `exists` reports a binary to be in the
@@ -107,7 +107,7 @@ fn file_has_execute_permission(filepath: &str) -> bool {
 fn string_is_nonzero(string: &str) -> bool { !string.is_empty() }
 
 /// Returns true if the variable is an array and the array is not empty
-fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool {
+fn array_var_is_not_empty(arrayvar: &str, shell: &Shell<'_>) -> bool {
     match shell.variables().get_ref(arrayvar) {
         Some(Value::Array(array)) => !array.is_empty(),
         _ => false,
@@ -115,7 +115,7 @@ fn array_var_is_not_empty(arrayvar: &str, shell: &Shell) -> bool {
 }
 
 /// Returns true if the variable is a string and the string is not empty
-fn string_var_is_not_empty(stringvar: &str, shell: &Shell) -> bool {
+fn string_var_is_not_empty(stringvar: &str, shell: &Shell<'_>) -> bool {
     match shell.variables().get_str(stringvar) {
         Some(string) => !string.is_empty(),
         None => false,
@@ -123,7 +123,7 @@ fn string_var_is_not_empty(stringvar: &str, shell: &Shell) -> bool {
 }
 
 /// Returns true if a function with the given name is defined
-fn function_is_defined(function: &str, shell: &Shell) -> bool {
+fn function_is_defined(function: &str, shell: &Shell<'_>) -> bool {
     if let Some(Value::Function(_)) = shell.variables().get_ref(function) {
         true
     } else {
diff --git a/src/lib/builtins/functions.rs b/src/lib/builtins/functions.rs
index adc601b40d148319f8094e912447895726f9a4ef..f43973ebb13ae202582d2e1c5720289b4a3211dc 100644
--- a/src/lib/builtins/functions.rs
+++ b/src/lib/builtins/functions.rs
@@ -1,7 +1,7 @@
 use crate::shell::{status::Status, variables::Variables};
 use std::io::{self, Write};
 
-pub fn print_functions(vars: &Variables) -> Status {
+pub fn print_functions(vars: &Variables<'_>) -> Status {
     let stdout = io::stdout();
     let stdout = &mut stdout.lock();
     let _ = writeln!(stdout, "# Functions");
diff --git a/src/lib/builtins/is.rs b/src/lib/builtins/is.rs
index 0fb7b8550d42c8c76a3960da392cc6f89b2a274c..09276e712d82bc82900f4a268f9d4dd2e61efb4a 100644
--- a/src/lib/builtins/is.rs
+++ b/src/lib/builtins/is.rs
@@ -1,7 +1,7 @@
 use crate::{shell::Shell, status::Status, types};
 use small;
 
-pub fn is(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn is(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     match args.len() {
         4 => {
             if args[1] != "not" {
@@ -21,7 +21,7 @@ pub fn is(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-fn eval_arg(arg: &str, shell: &mut Shell) -> types::Str {
+fn eval_arg(arg: &str, shell: &mut Shell<'_>) -> types::Str {
     let value = get_var_string(arg, shell);
     if &*value != "" {
         return value;
@@ -30,7 +30,7 @@ fn eval_arg(arg: &str, shell: &mut Shell) -> types::Str {
 }
 
 // On error returns an empty String.
-fn get_var_string(name: &str, shell: &mut Shell) -> types::Str {
+fn get_var_string(name: &str, shell: &mut Shell<'_>) -> types::Str {
     if name.chars().nth(0).unwrap() != '$' {
         return "".into();
     }
diff --git a/src/lib/builtins/job_control.rs b/src/lib/builtins/job_control.rs
index c419450212318a6038ac1ca96cf1daffabdf6d47..19a56f31a3d3a69d2ab4207c4f2384e53504dd92 100644
--- a/src/lib/builtins/job_control.rs
+++ b/src/lib/builtins/job_control.rs
@@ -8,7 +8,7 @@ use smallvec::SmallVec;
 /// Disowns given process job IDs, and optionally marks jobs to not receive SIGHUP signals.
 /// The `-a` flag selects all jobs, `-r` selects all running jobs, and `-h` specifies to mark
 /// SIGHUP ignoral.
-pub fn disown(shell: &mut Shell, args: &[small::String]) -> Result<(), String> {
+pub fn disown(shell: &mut Shell<'_>, args: &[small::String]) -> Result<(), String> {
     // Specifies that a process should be set to not receive SIGHUP signals.
     let mut no_sighup = false;
     // Specifies that all jobs in the process table should be manipulated.
@@ -62,7 +62,7 @@ pub fn disown(shell: &mut Shell, args: &[small::String]) -> Result<(), String> {
 }
 
 /// Display a list of all jobs running in the background.
-pub fn jobs(shell: &mut Shell) {
+pub fn jobs(shell: &mut Shell<'_>) {
     for (id, process) in shell.background_jobs().iter().enumerate() {
         if process.exists() {
             eprintln!("[{}] {}", id, process);
@@ -73,8 +73,8 @@ pub fn jobs(shell: &mut Shell) {
 /// Hands control of the foreground process to the specified jobs, recording their exit status.
 /// If the job is stopped, the job will be resumed.
 /// If multiple jobs are given, then only the last job's exit status will be returned.
-pub fn fg(shell: &mut Shell, args: &[small::String]) -> Status {
-    fn fg_job(shell: &mut Shell, njob: usize) -> Status {
+pub fn fg(shell: &mut Shell<'_>, args: &[small::String]) -> Status {
+    fn fg_job(shell: &mut Shell<'_>, njob: usize) -> Status {
         if let Some(job) = shell.background_jobs().iter().nth(njob).filter(|p| p.exists()) {
             // Give the bg task the foreground, and wait for it to finish. Also resume it if it
             // isn't running
@@ -85,29 +85,30 @@ pub fn fg(shell: &mut Shell, args: &[small::String]) -> Status {
         }
     }
 
-    let mut status = Status::SUCCESS;
     if args.is_empty() {
-        status = if let Some(previous_job) = shell.previous_job() {
+        if let Some(previous_job) = shell.previous_job() {
             fg_job(shell, previous_job)
         } else {
-            Status::error(format!("ion: fg: no jobs are running in the background"))
-        };
+            Status::error("ion: fg: no jobs are running in the background")
+        }
     } else {
         for arg in args {
             match arg.parse::<usize>() {
-                Ok(njob) => status = fg_job(shell, njob),
+                Ok(njob) => {
+                    fg_job(shell, njob);
+                }
                 Err(_) => {
-                    status = Status::error(format!("ion: fg: {} is not a valid job number", arg))
+                    return Status::error(format!("ion: fg: {} is not a valid job number", arg))
                 }
             }
         }
+        Status::SUCCESS
     }
-    status
 }
 
 /// Resumes a stopped background process, if it was stopped.
-pub fn bg(shell: &mut Shell, args: &[small::String]) -> Status {
-    fn bg_job(shell: &mut Shell, njob: usize) -> Status {
+pub fn bg(shell: &mut Shell<'_>, args: &[small::String]) -> Status {
+    fn bg_job(shell: &mut Shell<'_>, njob: usize) -> Status {
         if let Some(job) = shell.background_jobs().iter().nth(njob).filter(|p| p.exists()) {
             if job.is_running() {
                 Status::error(format!("ion: bg: job {} is already running", njob))
@@ -124,7 +125,7 @@ pub fn bg(shell: &mut Shell, args: &[small::String]) -> Status {
         if let Some(previous_job) = shell.previous_job() {
             bg_job(shell, previous_job)
         } else {
-            Status::error(format!("ion: bg: no jobs are running in the background"))
+            Status::error("ion: bg: no jobs are running in the background")
         }
     } else {
         for arg in args {
diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs
index d4e26d975f4d3ce9697c80e597da47006c88e61f..c591c1a5e38c0a60a08126dae26a8cb569e73b70 100644
--- a/src/lib/builtins/mod.rs
+++ b/src/lib/builtins/mod.rs
@@ -53,7 +53,7 @@ const DISOWN_DESC: &str =
     "Disowning a process removes that process from the shell's background process table.";
 
 /// The type for builtin functions. Builtins have direct access to the shell
-pub type BuiltinFunction<'a> = &'a dyn Fn(&[small::String], &mut Shell) -> Status;
+pub type BuiltinFunction<'a> = &'a dyn Fn(&[small::String], &mut Shell<'_>) -> Status;
 
 macro_rules! map {
     ($builtins:ident, $($name:expr => $func:ident: $help:expr),+) => {{
@@ -245,20 +245,22 @@ impl<'a> BuiltinMap<'a> {
     }
 }
 
-fn starts_with(args: &[small::String], _: &mut Shell) -> Status {
+fn starts_with(args: &[small::String], _: &mut Shell<'_>) -> Status {
     Status::from_exit_code(conditionals::starts_with(args))
 }
-fn ends_with(args: &[small::String], _: &mut Shell) -> Status {
+fn ends_with(args: &[small::String], _: &mut Shell<'_>) -> Status {
     Status::from_exit_code(conditionals::ends_with(args))
 }
-fn contains(args: &[small::String], _: &mut Shell) -> Status {
+fn contains(args: &[small::String], _: &mut Shell<'_>) -> Status {
     Status::from_exit_code(conditionals::contains(args))
 }
 
 // Definitions of simple builtins go here
-pub fn builtin_status(args: &[small::String], shell: &mut Shell) -> Status { status(args, shell) }
+pub fn builtin_status(args: &[small::String], shell: &mut Shell<'_>) -> Status {
+    status(args, shell)
+}
 
-pub fn builtin_cd(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_cd(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_CD) {
         return Status::SUCCESS;
     }
@@ -272,7 +274,7 @@ pub fn builtin_cd(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_bool(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_bool(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if args.len() != 2 {
         return Status::error("bool requires one argument");
     }
@@ -293,7 +295,7 @@ pub fn builtin_bool(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-pub fn builtin_is(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_is(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_IS) {
         return Status::SUCCESS;
     }
@@ -301,9 +303,9 @@ pub fn builtin_is(args: &[small::String], shell: &mut Shell) -> Status {
     is(args, shell)
 }
 
-pub fn builtin_dirs(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_dirs(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     // converts pbuf to an absolute path if possible
-    fn try_abs_path(pbuf: &PathBuf) -> Cow<str> {
+    fn try_abs_path(pbuf: &PathBuf) -> Cow<'_, str> {
         Cow::Owned(
             pbuf.canonicalize().unwrap_or_else(|_| pbuf.clone()).to_string_lossy().to_string(),
         )
@@ -337,7 +339,7 @@ pub fn builtin_dirs(args: &[small::String], shell: &mut Shell) -> Status {
         shell.clear_dir_stack();
     }
 
-    let mapper: fn((usize, &PathBuf)) -> Cow<str> = match (abs_pathnames, index) {
+    let mapper: fn((usize, &PathBuf)) -> Cow<'_, str> = match (abs_pathnames, index) {
         // ABS, INDEX
         (true, true) => |(num, x)| Cow::Owned(format!(" {}  {}", num, try_abs_path(x))),
         (true, false) => |(_, x)| try_abs_path(x),
@@ -368,7 +370,7 @@ pub fn builtin_dirs(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_pushd(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_pushd(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_PUSHD) {
         return Status::SUCCESS;
     }
@@ -435,7 +437,7 @@ pub fn builtin_pushd(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-pub fn builtin_popd(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_popd(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_POPD) {
         return Status::SUCCESS;
     }
@@ -496,18 +498,18 @@ pub fn builtin_popd(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_alias(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_alias(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     let args_str = args[1..].join(" ");
     alias(shell.variables_mut(), &args_str)
 }
 
-pub fn builtin_unalias(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_unalias(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     drop_alias(shell.variables_mut(), args)
 }
 
 // TODO There is a man page for fn however the -h and --help flags are not
 // checked for.
-pub fn builtin_fn(_: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_fn(_: &[small::String], shell: &mut Shell<'_>) -> Status {
     print_functions(shell.variables())
 }
 
@@ -517,7 +519,7 @@ impl Completer for EmptyCompleter {
     fn completions(&mut self, _start: &str) -> Vec<String> { Vec::new() }
 }
 
-pub fn builtin_read(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_read(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_READ) {
         return Status::SUCCESS;
     }
@@ -545,7 +547,7 @@ pub fn builtin_read(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-pub fn builtin_drop(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_drop(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_DROP) {
         return Status::SUCCESS;
     }
@@ -556,14 +558,14 @@ pub fn builtin_drop(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_set(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_set(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_SET) {
         return Status::SUCCESS;
     }
     set::set(args, shell)
 }
 
-pub fn builtin_eq(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_eq(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_EQ) {
         return Status::SUCCESS;
     }
@@ -571,17 +573,17 @@ pub fn builtin_eq(args: &[small::String], shell: &mut Shell) -> Status {
     is(args, shell)
 }
 
-pub fn builtin_eval(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_eval(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_EVAL) {
         Status::SUCCESS
     } else {
         shell.execute_command(args[1..].join(" ").as_bytes()).unwrap_or_else(|_| {
-            Status::error(format!("ion: supplied eval expression was not terminated"))
+            Status::error("ion: supplied eval expression was not terminated".to_string())
         })
     }
 }
 
-pub fn builtin_source(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_source(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_SOURCE) {
         return Status::SUCCESS;
     }
@@ -591,7 +593,7 @@ pub fn builtin_source(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_echo(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_echo(args: &[small::String], _: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_ECHO) {
         return Status::SUCCESS;
     }
@@ -601,7 +603,7 @@ pub fn builtin_echo(args: &[small::String], _: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_test(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_test(args: &[small::String], _: &mut Shell<'_>) -> Status {
     // Do not use `check_help` for the `test` builtin. The
     // `test` builtin contains a "-h" option.
     match test(args) {
@@ -612,14 +614,14 @@ pub fn builtin_test(args: &[small::String], _: &mut Shell) -> Status {
 }
 
 // TODO create manpage.
-pub fn builtin_calc(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_calc(args: &[small::String], _: &mut Shell<'_>) -> Status {
     match calc::calc(&args[1..]) {
         Ok(()) => Status::SUCCESS,
         Err(why) => Status::error(why),
     }
 }
 
-pub fn builtin_random(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_random(args: &[small::String], _: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_RANDOM) {
         return Status::SUCCESS;
     }
@@ -629,12 +631,12 @@ pub fn builtin_random(args: &[small::String], _: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_true(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_true(args: &[small::String], _: &mut Shell<'_>) -> Status {
     check_help(args, MAN_TRUE);
     Status::SUCCESS
 }
 
-pub fn builtin_false(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_false(args: &[small::String], _: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_FALSE) {
         return Status::SUCCESS;
     }
@@ -642,32 +644,32 @@ pub fn builtin_false(args: &[small::String], _: &mut Shell) -> Status {
 }
 
 // TODO create a manpage
-pub fn builtin_wait(_: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_wait(_: &[small::String], shell: &mut Shell<'_>) -> Status {
     shell.wait_for_background();
     Status::SUCCESS
 }
 
-pub fn builtin_jobs(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_jobs(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     check_help(args, MAN_JOBS);
     job_control::jobs(shell);
     Status::SUCCESS
 }
 
-pub fn builtin_bg(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_bg(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_BG) {
         return Status::SUCCESS;
     }
     job_control::bg(shell, &args[1..])
 }
 
-pub fn builtin_fg(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_fg(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_FG) {
         return Status::SUCCESS;
     }
     job_control::fg(shell, &args[1..])
 }
 
-pub fn builtin_suspend(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_suspend(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_SUSPEND) {
         return Status::SUCCESS;
     }
@@ -675,7 +677,7 @@ pub fn builtin_suspend(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-pub fn builtin_disown(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_disown(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     for arg in args {
         if *arg == "--help" {
             println!("{}", MAN_DISOWN);
@@ -688,7 +690,7 @@ pub fn builtin_disown(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_help(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_help(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if let Some(command) = args.get(1) {
         if let Some(help) = shell.builtins().get_help(command) {
             println!("{}", help);
@@ -701,7 +703,7 @@ pub fn builtin_help(args: &[small::String], shell: &mut Shell) -> Status {
     Status::SUCCESS
 }
 
-pub fn builtin_exit(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_exit(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_EXIT) {
         return Status::SUCCESS;
     }
@@ -718,7 +720,7 @@ pub fn builtin_exit(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_exec(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_exec(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     match exec(shell, &args[1..]) {
         // Shouldn't ever hit this case.
         Ok(()) => Status::SUCCESS,
@@ -727,7 +729,7 @@ pub fn builtin_exec(args: &[small::String], shell: &mut Shell) -> Status {
 }
 
 use regex::Regex;
-pub fn builtin_matches(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_matches(args: &[small::String], _: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_MATCHES) {
         return Status::SUCCESS;
     }
@@ -750,7 +752,7 @@ pub fn builtin_matches(args: &[small::String], _: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_exists(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_exists(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_EXISTS) {
         return Status::SUCCESS;
     }
@@ -761,21 +763,21 @@ pub fn builtin_exists(args: &[small::String], shell: &mut Shell) -> Status {
     }
 }
 
-pub fn builtin_which(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_which(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     match which(args, shell) {
         Ok(result) => result,
         Err(()) => Status::error(""),
     }
 }
 
-pub fn builtin_type(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn builtin_type(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     match find_type(args, shell) {
         Ok(result) => result,
         Err(()) => Status::error(""),
     }
 }
 
-pub fn builtin_isatty(args: &[small::String], _: &mut Shell) -> Status {
+pub fn builtin_isatty(args: &[small::String], _: &mut Shell<'_>) -> Status {
     if check_help(args, MAN_ISATTY) {
         return Status::SUCCESS;
     }
diff --git a/src/lib/builtins/set.rs b/src/lib/builtins/set.rs
index de2095a6c0475ffad47208f9dae14e0a1f433e5f..a2e2f36db25869ee1e5bf170d3f71f18c1cdab9b 100644
--- a/src/lib/builtins/set.rs
+++ b/src/lib/builtins/set.rs
@@ -12,7 +12,7 @@ enum PositionalArgs {
 
 use self::PositionalArgs::*;
 
-pub fn set(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn set(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     let mut args_iter = args.iter();
     let mut positionals = None;
 
@@ -42,10 +42,10 @@ pub fn set(args: &[small::String], shell: &mut Shell) -> Status {
                     b'o' => match args_iter.next().map(|s| s as &str) {
                         Some("huponexit") => shell.opts_mut().huponexit = false,
                         Some(_) => {
-                            return Status::error(format!("ion: set: invalid option"));
+                            return Status::error("ion: set: invalid option");
                         }
                         None => {
-                            return Status::error(format!("ion: set: no option given"));
+                            return Status::error("ion: set: no option given");
                         }
                     },
                     _ => return Status::SUCCESS,
@@ -62,7 +62,7 @@ pub fn set(args: &[small::String], shell: &mut Shell) -> Status {
                 // This used to take a `&[String]` but cloned them all, so although
                 // this is non-ideal and could probably be better done with `Rc`, it
                 // hasn't got any slower.
-                let arguments: types::Array =
+                let arguments: types::Array<'_> =
                     iter::once(command).chain(args_iter.cloned().map(Value::Str)).collect();
                 match kind {
                     UnsetIfNone => {
diff --git a/src/lib/builtins/source.rs b/src/lib/builtins/source.rs
index 7319fe4f6a4f063c5775da6be36735eb0fad7bb3..1124ae4ba9889bfb49d8ea930f812c8b66681252 100644
--- a/src/lib/builtins/source.rs
+++ b/src/lib/builtins/source.rs
@@ -3,7 +3,7 @@ use small;
 use std::fs::File;
 
 /// Evaluates the given file and returns 'SUCCESS' if it succeeds.
-pub fn source(shell: &mut Shell, arguments: &[small::String]) -> Result<(), String> {
+pub fn source(shell: &mut Shell<'_>, arguments: &[small::String]) -> Result<(), String> {
     match arguments.get(1) {
         Some(argument) => {
             if let Ok(file) = File::open(argument.as_str()) {
diff --git a/src/lib/builtins/status.rs b/src/lib/builtins/status.rs
index ca6fdbbc89f69626c6649a9f55e41917c3b65dc7..86f5852e580c83a44969a2e9ba5cc2075a220d8b 100644
--- a/src/lib/builtins/status.rs
+++ b/src/lib/builtins/status.rs
@@ -5,7 +5,7 @@ use crate::{
 use small;
 use std::env;
 
-pub fn status(args: &[small::String], shell: &mut Shell) -> Status {
+pub fn status(args: &[small::String], shell: &mut Shell<'_>) -> Status {
     let mut help = false;
     let mut login_shell = false;
     let mut interactive = false;
diff --git a/src/lib/builtins/variables.rs b/src/lib/builtins/variables.rs
index bef81a0d270eddac0840aa1e3f0e71435bede848..686510aaf2aa19d7d36e6a57c60e7f7dc49974ba 100644
--- a/src/lib/builtins/variables.rs
+++ b/src/lib/builtins/variables.rs
@@ -7,7 +7,7 @@ use crate::{
     types,
 };
 
-fn print_list(vars: &Variables) {
+fn print_list(vars: &Variables<'_>) {
     let stdout = io::stdout();
     let stdout = &mut stdout.lock();
 
@@ -65,7 +65,7 @@ fn parse_alias(args: &str) -> Binding {
 
 /// The `alias` command will define an alias for another command, and thus may be used as a
 /// command itself.
-pub fn alias(vars: &mut Variables, args: &str) -> Status {
+pub fn alias(vars: &mut Variables<'_>, args: &str) -> Status {
     match parse_alias(args) {
         Binding::InvalidKey(key) => {
             return Status::error(format!("ion: alias name, '{}', is invalid", key));
@@ -82,9 +82,9 @@ pub fn alias(vars: &mut Variables, args: &str) -> Status {
 }
 
 /// Dropping an alias will erase it from the shell.
-pub fn drop_alias<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> Status {
+pub fn drop_alias<S: AsRef<str>>(vars: &mut Variables<'_>, args: &[S]) -> Status {
     if args.len() <= 1 {
-        return Status::error(format!("ion: you must specify an alias name"));
+        return Status::error("ion: you must specify an alias name".to_string());
     }
     for alias in args.iter().skip(1) {
         if vars.remove_variable(alias.as_ref()).is_none() {
@@ -95,13 +95,13 @@ pub fn drop_alias<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> Status {
 }
 
 /// Dropping an array will erase it from the shell.
-pub fn drop_array<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> Status {
+pub fn drop_array<S: AsRef<str>>(vars: &mut Variables<'_>, args: &[S]) -> Status {
     if args.len() <= 2 {
-        return Status::error(format!("ion: you must specify an array name"));
+        return Status::error("ion: you must specify an array name".to_string());
     }
 
     if args[1].as_ref() != "-a" {
-        return Status::error(format!("ion: drop_array must be used with -a option"));
+        return Status::error("ion: drop_array must be used with -a option".to_string());
     }
 
     for array in args.iter().skip(2) {
@@ -113,9 +113,9 @@ pub fn drop_array<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> Status {
 }
 
 /// Dropping a variable will erase it from the shell.
-pub fn drop_variable<S: AsRef<str>>(vars: &mut Variables, args: &[S]) -> Status {
+pub fn drop_variable<S: AsRef<str>>(vars: &mut Variables<'_>, args: &[S]) -> Status {
     if args.len() <= 1 {
-        return Status::error(format!("ion: you must specify a variable name"));
+        return Status::error("ion: you must specify a variable name".to_string());
     }
 
     for variable in args.iter().skip(1) {
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index a0d5413b3faea3b09576ddc3e53f1eb05f395b61..f7738bfabc292fa676c6c6b797e33c040f1f938e 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -1,13 +1,10 @@
 #![allow(unknown_lints)]
 
-#[macro_use]
-extern crate doc_comment;
-#[macro_use]
-extern crate err_derive;
-extern crate ion_braces as braces;
-extern crate ion_lexers as lexers;
-extern crate ion_ranges as ranges;
-extern crate ion_sys as sys;
+use doc_comment::doctest;
+use ion_braces as braces;
+use ion_lexers as lexers;
+use ion_ranges as ranges;
+use ion_sys as sys;
 
 #[macro_use]
 pub mod types;
diff --git a/src/lib/parser/assignments/actions.rs b/src/lib/parser/assignments/actions.rs
index 777fa8430eace911f86e88107a5cb0a144ce1ee4..b9050e0278e284ad9162df7b987a0f0d2acdac71 100644
--- a/src/lib/parser/assignments/actions.rs
+++ b/src/lib/parser/assignments/actions.rs
@@ -16,7 +16,7 @@ pub enum AssignmentError<'a> {
 }
 
 impl<'a> Display for AssignmentError<'a> {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         match *self {
             AssignmentError::InvalidValue(ref expected, ref actual) => {
                 write!(f, "expected {}, but received {}", expected, actual)
diff --git a/src/lib/parser/assignments/checker.rs b/src/lib/parser/assignments/checker.rs
index 539072100d9312b462533f1b8c326762f50295ce..c010bcd9e9ab7dc0a94f9a1a0df851d4d625e38f 100644
--- a/src/lib/parser/assignments/checker.rs
+++ b/src/lib/parser/assignments/checker.rs
@@ -146,7 +146,7 @@ pub fn value_check<E: Expander>(
 #[cfg(test)]
 mod test {
     use super::*;
-    use lexers::TypeError;
+    use crate::lexers::TypeError;
 
     struct VariableExpander;
 
diff --git a/src/lib/parser/loops.rs b/src/lib/parser/loops.rs
index 2c74c8ac96d64ef461a12a479b7e3e57f142f5dd..478cf1903227a3be9120064c06e7502811084442 100644
--- a/src/lib/parser/loops.rs
+++ b/src/lib/parser/loops.rs
@@ -1,10 +1,10 @@
-use crate::{parser::Expander, types};
+use crate::{parser::Expander, ranges, types};
 
 /// The expression given to a for loop as the value to iterate upon.
 pub enum ForValueExpression {
     Multiple(Vec<types::Str>),
     Normal(types::Str),
-    Range(Box<Iterator<Item = ::small::String> + 'static>),
+    Range(Box<dyn Iterator<Item = small::String> + 'static>),
 }
 
 impl ForValueExpression {
@@ -14,9 +14,7 @@ impl ForValueExpression {
 
         if output.is_empty() {
             ForValueExpression::Multiple(output)
-        } else if let (Some(range), true) =
-            (crate::ranges::parse_range(&output[0]), output.len() == 1)
-        {
+        } else if let (Some(range), true) = (ranges::parse_range(&output[0]), output.len() == 1) {
             ForValueExpression::Range(range)
         } else if output.len() > 1 {
             ForValueExpression::Multiple(output)
diff --git a/src/lib/parser/pipelines/mod.rs b/src/lib/parser/pipelines/mod.rs
index 7919b82f3f42a2a79f017230644754ccae4d3dcf..7ecbbe63b7619897139cf1859aad96b22d886b80 100644
--- a/src/lib/parser/pipelines/mod.rs
+++ b/src/lib/parser/pipelines/mod.rs
@@ -38,7 +38,7 @@ pub enum Input {
 }
 
 impl<'a> fmt::Display for Input {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Input::File(ref file) => write!(f, "< {}", file),
             Input::HereString(ref string) => write!(f, "<<< '{}'", string),
@@ -47,7 +47,7 @@ impl<'a> fmt::Display for Input {
 }
 
 impl<'a> fmt::Display for Redirection {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "{}>{} {}",
@@ -70,7 +70,11 @@ pub enum PipeType {
     Disown,
 }
 
-#[derive(Debug, PartialEq, Clone)]
+impl Default for PipeType {
+    fn default() -> Self { PipeType::Normal }
+}
+
+#[derive(Default, Debug, PartialEq, Clone)]
 pub struct Pipeline<'a> {
     pub items: Vec<PipeItem<'a>>,
     pub pipe:  PipeType,
@@ -107,7 +111,7 @@ impl<'a> PipeItem<'a> {
 }
 
 impl<'a> fmt::Display for PipeItem<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.job.args.iter().format(" "))?;
         for input in &self.inputs {
             write!(f, " {}", input)?;
@@ -140,11 +144,11 @@ impl<'a> Pipeline<'a> {
         self.items.iter_mut().for_each(|i| i.expand(shell));
     }
 
-    pub fn new() -> Self { Pipeline { items: Vec::new(), pipe: PipeType::Normal } }
+    pub fn new() -> Self { Self::default() }
 }
 
 impl<'a> fmt::Display for Pipeline<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "{}{}",
diff --git a/src/lib/parser/shell_expand/mod.rs b/src/lib/parser/shell_expand/mod.rs
index a2a5ed9619db40f7e150edab04f427124551c521..b47ec937b0b6158decf3441db8209346faa847ab 100644
--- a/src/lib/parser/shell_expand/mod.rs
+++ b/src/lib/parser/shell_expand/mod.rs
@@ -141,7 +141,7 @@ trait ExpanderInternal: Expander {
         for word in nodes.iter().flat_map(|node| self.expand_string_no_glob(node)) {
             match parse_range(&word) {
                 Some(elements) => temp.extend(elements),
-                None => temp.push(word.into()),
+                None => temp.push(word),
             }
         }
         if !temp.is_empty() {
@@ -227,7 +227,7 @@ trait ExpanderInternal: Expander {
         self.expand_tokens(&token_buffer, contains_brace)
     }
 
-    fn expand_braces(&self, word_tokens: &[WordToken]) -> types::Args {
+    fn expand_braces(&self, word_tokens: &[WordToken<'_>]) -> types::Args {
         let mut expanded_words = types::Args::new();
         let mut output = small::String::new();
         let tokens: &mut Vec<BraceToken> = &mut Vec::new();
@@ -338,7 +338,7 @@ trait ExpanderInternal: Expander {
     }
 
     #[auto_enum]
-    fn expand_single_array_token(&self, token: &WordToken) -> Option<types::Args> {
+    fn expand_single_array_token(&self, token: &WordToken<'_>) -> Option<types::Args> {
         match *token {
             WordToken::Array(ref elements, ref index) => Some(self.array_expand(elements, &index)),
             WordToken::ArrayVariable(array, quoted, ref index) => match self.array(array, index) {
@@ -395,7 +395,7 @@ trait ExpanderInternal: Expander {
         }
     }
 
-    fn expand_single_string_token(&self, token: &WordToken) -> types::Args {
+    fn expand_single_string_token(&self, token: &WordToken<'_>) -> types::Args {
         let mut output = small::String::new();
         let mut expanded_words = types::Args::new();
 
@@ -483,7 +483,7 @@ trait ExpanderInternal: Expander {
         }
     }
 
-    fn expand_tokens(&self, token_buffer: &[WordToken], contains_brace: bool) -> types::Args {
+    fn expand_tokens(&self, token_buffer: &[WordToken<'_>], contains_brace: bool) -> types::Args {
         if !token_buffer.is_empty() {
             if contains_brace {
                 return self.expand_braces(&token_buffer);
@@ -606,7 +606,7 @@ trait ExpanderInternal: Expander {
 
                 for c in input.bytes() {
                     match c {
-                        48...57 | 65...90 | 95 | 97...122 => {
+                        48..=57 | 65..=90 | 95 | 97..=122 => {
                             varbuf.push(c as char);
                         }
                         _ => {
diff --git a/src/lib/parser/shell_expand/words/methods/mod.rs b/src/lib/parser/shell_expand/words/methods/mod.rs
index c8fe7cb9c884bfea602a62c2c978ca2e8821b74e..e4d4e4dc0d6c99081ef3ed1717fda95b65df5084 100644
--- a/src/lib/parser/shell_expand/words/methods/mod.rs
+++ b/src/lib/parser/shell_expand/words/methods/mod.rs
@@ -15,7 +15,7 @@ pub enum Pattern<'a> {
 }
 
 #[derive(Debug)]
-pub struct MethodArgs<'a, 'b, E: 'b + Expander> {
+pub struct MethodArgs<'a, 'b, E: Expander> {
     args:   &'a str,
     expand: &'b E,
 }
diff --git a/src/lib/parser/shell_expand/words/mod.rs b/src/lib/parser/shell_expand/words/mod.rs
index 5c569b948cb61e959a8dbf056f92b5c4d49995d0..dad9cf2b748d0e74a29b982080bd20ceface8274 100644
--- a/src/lib/parser/shell_expand/words/mod.rs
+++ b/src/lib/parser/shell_expand/words/mod.rs
@@ -16,8 +16,8 @@ enum Quotes {
 }
 
 /// Unescapes filenames to be passed into the completer
-pub fn unescape(input: &str) -> Cow<str> {
-    let mut input: Cow<str> = input.into();
+pub fn unescape(input: &str) -> Cow<'_, str> {
+    let mut input: Cow<'_, str> = input.into();
     while let Some(found) = input.find('\\') {
         if input.as_ref().len() > found + 1 {
             input.to_mut().remove(found);
@@ -46,7 +46,7 @@ pub enum WordToken<'a> {
 }
 
 #[derive(Debug)]
-pub struct WordIterator<'a, E: Expander + 'a> {
+pub struct WordIterator<'a, E: Expander> {
     data:      &'a str,
     read:      usize,
     quotes:    Quotes,
@@ -342,7 +342,7 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> {
                     );
                 }
                 // Only alphanumerical and underscores are allowed in variable names
-                0...47 | 58...64 | 91...94 | 96 | 123...127 => {
+                0..=47 | 58..=64 | 91..=94 | 96 | 123..=127 => {
                     return WordToken::ArrayVariable(
                         &self.data[start..self.read],
                         self.quotes == Quotes::Double,
@@ -460,7 +460,7 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> {
                     );
                 }
                 // Only alphanumerical and underscores are allowed in variable names
-                0...47 | 58...64 | 91...94 | 96 | 123...127 => {
+                0..=47 | 58..=64 | 91..=94 | 96 | 123..=127 => {
                     return WordToken::ArrayVariable(
                         &self.data[start..self.read],
                         self.quotes == Quotes::Double,
@@ -587,7 +587,7 @@ impl<'a, E: Expander + 'a> WordIterator<'a, E> {
                     panic!("ion: fatal error with syntax validation parsing: unterminated method");
                 }
                 // Only alphanumerical and underscores are allowed in variable names
-                0...47 | 58...64 | 91...94 | 96 | 123...127 => {
+                0..=47 | 58..=64 | 91..=94 | 96 | 123..=127 => {
                     let variable = &self.data[start..self.read];
 
                     return if character == b'[' {
diff --git a/src/lib/parser/shell_expand/words/tests.rs b/src/lib/parser/shell_expand/words/tests.rs
index 18a90a3f0f2f96f3fcecd183bcea08f25c39038b..92666f94184d7c9127503ea75727e106dbb10b4c 100644
--- a/src/lib/parser/shell_expand/words/tests.rs
+++ b/src/lib/parser/shell_expand/words/tests.rs
@@ -8,7 +8,7 @@ struct Empty;
 
 impl Expander for Empty {}
 
-fn compare(input: &str, expected: Vec<WordToken>) {
+fn compare(input: &str, expected: Vec<WordToken<'_>>) {
     let mut correct = 0;
     for (actual, expected) in WordIterator::new(input, &Empty, true).zip(expected.iter()) {
         assert_eq!(actual, *expected, "{:?} != {:?}", actual, expected);
diff --git a/src/lib/parser/statement/case.rs b/src/lib/parser/statement/case.rs
index 5246c20c3cc9d55f0cfc8a676822f5522dd69012..03953664ab24dd82523a080a949aec2c2682c03d 100644
--- a/src/lib/parser/statement/case.rs
+++ b/src/lib/parser/statement/case.rs
@@ -10,7 +10,7 @@ pub enum CaseError<'a> {
 }
 
 impl<'a> Display for CaseError<'a> {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         match *self {
             CaseError::NoBindVariable => write!(f, "no bind variable was supplied"),
             CaseError::NoConditional => write!(f, "no conditional statement was given"),
@@ -22,7 +22,9 @@ impl<'a> Display for CaseError<'a> {
     }
 }
 
-pub fn parse_case(data: &str) -> Result<(Option<&str>, Option<&str>, Option<String>), CaseError> {
+pub fn parse_case(
+    data: &str,
+) -> Result<(Option<&str>, Option<&str>, Option<String>), CaseError<'_>> {
     let mut splitter = ArgumentSplitter::new(data);
     // let argument = splitter.next().ok_or(CaseError::Empty)?;
     let mut argument = None;
diff --git a/src/lib/parser/statement/functions.rs b/src/lib/parser/statement/functions.rs
index c92774c1a833cb00a3e207986f7de380db7aa520..c4f3ddf7398fa5477161e0994710a99545d02af4 100644
--- a/src/lib/parser/statement/functions.rs
+++ b/src/lib/parser/statement/functions.rs
@@ -9,7 +9,7 @@ pub enum FunctionParseError {
 }
 
 impl<'a> Display for FunctionParseError {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         match *self {
             FunctionParseError::RepeatedArgument(ref arg) => {
                 write!(f, "repeated argument name: '{}'", arg)
@@ -22,7 +22,7 @@ impl<'a> Display for FunctionParseError {
 /// The arguments expression given to a function declaration goes into here, which will be
 /// converted into a tuple consisting of a `KeyIterator` iterator, which will collect type
 /// information, and an optional description of the function.
-pub fn parse_function(arg: &str) -> (KeyIterator, Option<&str>) {
+pub fn parse_function(arg: &str) -> (KeyIterator<'_>, Option<&str>) {
     let (args, description) = split_pattern(arg, "--");
     (KeyIterator::new(args), description)
 }
@@ -31,7 +31,7 @@ pub fn parse_function(arg: &str) -> (KeyIterator, Option<&str>) {
 /// type or argument error is detected, then that error will be returned instead. This is required
 /// because of lifetime restrictions on `KeyIterator`, which will not live for the remainder of the
 /// declared function's lifetime.
-pub fn collect_arguments(args: KeyIterator) -> Result<Vec<KeyBuf>, FunctionParseError> {
+pub fn collect_arguments(args: KeyIterator<'_>) -> Result<Vec<KeyBuf>, FunctionParseError> {
     let mut keybuf: Vec<KeyBuf> = Vec::new();
     for arg in args {
         match arg {
diff --git a/src/lib/parser/statement/mod.rs b/src/lib/parser/statement/mod.rs
index 1863302b2497d9d8e237b019b25a2549235527ea..61fedacaa147cf5393f015dd650a8888a6d55618 100644
--- a/src/lib/parser/statement/mod.rs
+++ b/src/lib/parser/statement/mod.rs
@@ -15,7 +15,7 @@ use crate::{
 /// Parses a given statement string and return's the corresponding mapped
 /// `Statement`
 pub fn parse_and_validate<'b>(
-    statement: Result<StatementVariant, StatementError>,
+    statement: Result<StatementVariant<'_>, StatementError>,
     builtins: &BuiltinMap<'b>,
 ) -> Statement<'b> {
     match statement {
diff --git a/src/lib/parser/statement/splitter.rs b/src/lib/parser/statement/splitter.rs
index 5a0e0aa64bd9677b4cf73e1f56f985ca7e4b70e7..118fc54c3a9e21b73e0dbe2207d40a0c44a9ea67 100644
--- a/src/lib/parser/statement/splitter.rs
+++ b/src/lib/parser/statement/splitter.rs
@@ -24,7 +24,7 @@ pub enum StatementError {
 }
 
 impl Display for StatementError {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         match *self {
             StatementError::IllegalCommandName(ref command) => {
                 writeln!(f, "illegal command name: {}", command)
@@ -134,7 +134,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 }
                 b'\\' => self.skip = true,
                 // [^A-Za-z0-9_:,}]
-                0...43 | 45...47 | 59...64 | 91...94 | 96 | 123...124 | 126...127
+                0..=43 | 45..=47 | 59..=64 | 91..=94 | 96 | 123..=124 | 126..=127
                     if self.vbrace =>
                 {
                     // If we are just ending the braced section continue as normal
@@ -183,7 +183,7 @@ impl<'a> Iterator for StatementSplitter<'a> {
                 b')' => self.paren_level -= 1,
                 b'}' if self.vbrace => self.vbrace = false,
                 // [^A-Za-z0-9_]
-                0...37 | 39...47 | 58 | 60...64 | 91...94 | 96 | 126...127 => self.variable = false,
+                0..=37 | 39..=47 | 58 | 60..=64 | 91..=94 | 96 | 126..=127 => self.variable = false,
                 _ if self.quotes => {}
                 b'{' => self.brace_level += 1,
                 b'}' => {
diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs
index 2107dcab9fb0ec2c94514b05904e5a8f3f592efb..59e0e9bc4fb1e1aae417a6b45cea6ec9e7a66d9a 100644
--- a/src/lib/shell/assignments.rs
+++ b/src/lib/shell/assignments.rs
@@ -14,7 +14,7 @@ use std::{
     result::Result,
 };
 
-fn list_vars(shell: &Shell) -> Result<(), io::Error> {
+fn list_vars(shell: &Shell<'_>) -> Result<(), io::Error> {
     let stdout = io::stdout();
     let mut buffer = BufWriter::new(stdout.lock());
 
diff --git a/src/lib/shell/directory_stack.rs b/src/lib/shell/directory_stack.rs
index e8d22e47533b10046d3df1e9f7784a8e159817c4..236f3b9b7c4da69470b5b6d8567b1481e5217a1a 100644
--- a/src/lib/shell/directory_stack.rs
+++ b/src/lib/shell/directory_stack.rs
@@ -88,12 +88,12 @@ impl DirectoryStack {
         self.dirs.iter()
     }
 
-    fn insert_dir(&mut self, index: usize, path: PathBuf, variables: &Variables) {
+    fn insert_dir(&mut self, index: usize, path: PathBuf, variables: &Variables<'_>) {
         self.dirs.insert(index, path);
         self.dirs.truncate(DirectoryStack::get_size(variables));
     }
 
-    fn push_dir(&mut self, path: PathBuf, variables: &Variables) {
+    fn push_dir(&mut self, path: PathBuf, variables: &Variables<'_>) {
         self.dirs.push_front(path);
         self.dirs.truncate(DirectoryStack::get_size(variables));
     }
@@ -101,7 +101,7 @@ impl DirectoryStack {
     fn change_and_push_dir(
         &mut self,
         dir: &str,
-        variables: &Variables,
+        variables: &Variables<'_>,
     ) -> Result<(), Cow<'static, str>> {
         let new_dir = self.normalize_path(dir);
         set_current_dir_ion(&new_dir).map_err(|err| {
@@ -121,7 +121,7 @@ impl DirectoryStack {
 
     fn switch_to_previous_directory(
         &mut self,
-        variables: &Variables,
+        variables: &Variables<'_>,
     ) -> Result<(), Cow<'static, str>> {
         self.get_previous_dir()
             .ok_or(Cow::Borrowed("ion: no previous directory to switch to"))
@@ -132,7 +132,10 @@ impl DirectoryStack {
             })
     }
 
-    fn switch_to_home_directory(&mut self, variables: &Variables) -> Result<(), Cow<'static, str>> {
+    fn switch_to_home_directory(
+        &mut self,
+        variables: &Variables<'_>,
+    ) -> Result<(), Cow<'static, str>> {
         sys_env::home_dir().map_or(
             Err(Cow::Borrowed("ion: failed to get home directory")),
             |home| {
@@ -147,7 +150,7 @@ impl DirectoryStack {
     pub fn cd<T: AsRef<str>>(
         &mut self,
         dir: Option<T>,
-        variables: &Variables,
+        variables: &Variables<'_>,
     ) -> Result<(), Cow<'static, str>> {
         match dir {
             Some(dir) => {
@@ -187,7 +190,7 @@ impl DirectoryStack {
         &mut self,
         path: PathBuf,
         keep_front: bool,
-        variables: &mut Variables,
+        variables: &mut Variables<'_>,
     ) -> Result<(), Cow<'static, str>> {
         let index = if keep_front { 1 } else { 0 };
         let new_dir = self.normalize_path(path.to_str().unwrap());
@@ -206,7 +209,7 @@ impl DirectoryStack {
     /// directory stack size variable. If it succeeds, it will return the value of that
     /// variable,
     /// else it will return a default value of 1000.
-    fn get_size(variables: &Variables) -> usize {
+    fn get_size(variables: &Variables<'_>) -> usize {
         variables
             .get_str("DIRECTORY_STACK_SIZE")
             .unwrap_or_default()
diff --git a/src/lib/shell/flow.rs b/src/lib/shell/flow.rs
index dced4229476aeab90c00603ddb13e0cab0472c07..defffa95ae4d5fe4c37f1cd0ed90f2a5d4b99f22 100644
--- a/src/lib/shell/flow.rs
+++ b/src/lib/shell/flow.rs
@@ -312,7 +312,7 @@ impl<'a> Shell<'a> {
                         };
                         self.variables_mut().set(
                             &bind,
-                            value.iter().cloned().map(Value::Str).collect::<types::Array>(),
+                            value.iter().cloned().map(Value::Str).collect::<types::Array<'_>>(),
                         );
                         out
                     } else {
@@ -381,7 +381,7 @@ fn expand_pipeline<'a>(
     pipeline: &Pipeline<'a>,
 ) -> Result<(Pipeline<'a>, Vec<Statement<'a>>), String> {
     let mut item_iter = pipeline.items.iter();
-    let mut items: Vec<PipeItem> = Vec::with_capacity(item_iter.size_hint().0);
+    let mut items: Vec<PipeItem<'a>> = Vec::with_capacity(item_iter.size_hint().0);
     let mut statements = Vec::new();
 
     while let Some(item) = item_iter.next() {
diff --git a/src/lib/shell/flow_control.rs b/src/lib/shell/flow_control.rs
index cb2f25021680443b124e8d89f4e97d926e01f184..46bbceb8a54fef679842ff451851eebd1f104d1b 100644
--- a/src/lib/shell/flow_control.rs
+++ b/src/lib/shell/flow_control.rs
@@ -4,6 +4,7 @@ use crate::{
     shell::{status::Status, Shell},
     types,
 };
+use err_derive::Error;
 use small;
 use smallvec::SmallVec;
 
@@ -406,8 +407,8 @@ impl<'a> Function<'a> {
         description: Option<small::String>,
         name: types::Str,
         args: Vec<KeyBuf>,
-        statements: Vec<Statement>,
-    ) -> Function {
+        statements: Vec<Statement<'a>>,
+    ) -> Self {
         Function { description, name, args, statements }
     }
 }
diff --git a/src/lib/shell/fork.rs b/src/lib/shell/fork.rs
index 941330fbbca77a4082dfb03de46f21e4696e6ae9..0a663537027ae7034202de8fa7250fec4ef03e19 100644
--- a/src/lib/shell/fork.rs
+++ b/src/lib/shell/fork.rs
@@ -122,7 +122,7 @@ impl<'a, 'b> Fork<'a, 'b> {
                 drop(null_file);
 
                 // Obtain ownership of the child's copy of the shell, and then configure it.
-                let mut shell: Shell = unsafe { (self.shell as *const Shell).read() };
+                let mut shell: Shell<'b> = unsafe { (self.shell as *const Shell<'b>).read() };
                 shell.variables_mut().set("PID", sys::getpid().unwrap_or(0).to_string());
 
                 // Execute the given closure within the child's shell.
diff --git a/src/lib/shell/job.rs b/src/lib/shell/job.rs
index a6bd3155c9efd76e8b9a194e1d0059a36c565f46..3722740f03fb309e351950c02400d58c2859012e 100644
--- a/src/lib/shell/job.rs
+++ b/src/lib/shell/job.rs
@@ -19,7 +19,7 @@ impl<'a> Job<'a> {
 
     /// Takes the current job's arguments and expands them, one argument at a
     /// time, returning a new `Job` with the expanded arguments.
-    pub fn expand(&mut self, shell: &Shell) {
+    pub fn expand(&mut self, shell: &Shell<'_>) {
         match shell.variables.get_ref(&self.args[0]) {
             Some(Value::Function(_)) => {}
             _ => self.args = self.args.drain().flat_map(|arg| expand_arg(&arg, shell)).collect(),
@@ -36,13 +36,13 @@ impl<'a> Job<'a> {
 }
 
 impl<'a> PartialEq for Job<'a> {
-    fn eq(&self, other: &Job) -> bool {
+    fn eq(&self, other: &Job<'_>) -> bool {
         self.args == other.args && self.redirection == other.redirection
     }
 }
 
 impl<'a> fmt::Debug for Job<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "Job {{ command: {}, args: {:?}, redirection: {:?} }}",
@@ -52,7 +52,7 @@ impl<'a> fmt::Debug for Job<'a> {
 }
 
 /// Expands a given argument and returns it as an `Args`.
-fn expand_arg(arg: &str, shell: &Shell) -> types::Args {
+fn expand_arg(arg: &str, shell: &Shell<'_>) -> types::Args {
     let res = shell.expand_string(&arg);
     if res.is_empty() {
         args![""]
diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs
index 98b17e19fc6537599010128a63b99e902f2dc415..a211dd0995310f79893cc0535818ab486ef1c85a 100644
--- a/src/lib/shell/mod.rs
+++ b/src/lib/shell/mod.rs
@@ -29,6 +29,7 @@ use crate::{
     parser::{assignments::value_check, pipelines::Pipeline, Terminator},
     sys, types,
 };
+use err_derive::Error;
 use itertools::Itertools;
 use std::{
     borrow::Cow,
@@ -104,22 +105,22 @@ pub struct Shell<'a> {
     /// background process.
     foreground_signals: Arc<ForegroundSignals>,
     /// Custom callback to cleanup before exit
-    prep_for_exit: Option<Box<FnMut(&mut Shell) + 'a>>,
+    prep_for_exit: Option<Box<dyn FnMut(&mut Shell<'_>) + 'a>>,
     /// Custom callback for each command call
-    on_command: Option<Box<Fn(&Shell, std::time::Duration) + 'a>>,
+    on_command: Option<Box<dyn Fn(&Shell<'_>, std::time::Duration) + 'a>>,
 }
 
 pub struct EmptyBlockError;
 
 impl fmt::Display for EmptyBlockError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "Could not exit the current block since it does not exist!")
     }
 }
 
 // Implement std::fmt::Debug for AppError
 impl fmt::Debug for EmptyBlockError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "EmptyBlockError {{ file: {}, line: {} }}", file!(), line!())
     }
 }
@@ -218,7 +219,7 @@ impl<'a> Shell<'a> {
     }
 
     pub fn cd<T: AsRef<str>>(&mut self, dir: Option<T>) -> Result<(), Cow<'static, str>> {
-        self.directory_stack.cd(dir, &mut self.variables)
+        self.directory_stack.cd(dir, &self.variables)
     }
 
     pub fn pushd(&mut self, path: PathBuf, keep_front: bool) -> Result<(), Cow<'static, str>> {
@@ -413,14 +414,14 @@ impl<'a> Shell<'a> {
     }
 
     /// Set the callback to call before exiting the shell
-    pub fn set_prep_for_exit(&mut self, callback: Option<Box<dyn FnMut(&mut Shell) + 'a>>) {
+    pub fn set_prep_for_exit(&mut self, callback: Option<Box<dyn FnMut(&mut Shell<'_>) + 'a>>) {
         self.prep_for_exit = callback;
     }
 
     /// Set the callback to call on each command
     pub fn set_on_command(
         &mut self,
-        callback: Option<Box<dyn Fn(&Shell, std::time::Duration) + 'a>>,
+        callback: Option<Box<dyn Fn(&Shell<'_>, std::time::Duration) + 'a>>,
     ) {
         self.on_command = callback;
     }
@@ -475,7 +476,7 @@ impl<'a> Shell<'a> {
         process::exit(status.as_os_code());
     }
 
-    pub fn assign(&mut self, key: &Key, value: Value<'a>) -> Result<(), String> {
+    pub fn assign(&mut self, key: &Key<'_>, value: Value<'a>) -> Result<(), String> {
         match (&key.kind, &value) {
             (Primitive::Indexed(ref index_name, ref index_kind), Value::Str(_)) => {
                 let index = value_check(self, index_name, index_kind)
diff --git a/src/lib/shell/pipe_exec/job_control.rs b/src/lib/shell/pipe_exec/job_control.rs
index a3d362aa67917d2101bcd2dcffdafb351a013577..3487364c302f217689d5bc2e019da11b2d4aa208 100644
--- a/src/lib/shell/pipe_exec/job_control.rs
+++ b/src/lib/shell/pipe_exec/job_control.rs
@@ -24,7 +24,7 @@ pub enum ProcessState {
 }
 
 impl fmt::Display for ProcessState {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ProcessState::Running => write!(f, "Running"),
             ProcessState::Stopped => write!(f, "Stopped"),
@@ -64,7 +64,7 @@ impl BackgroundProcess {
 }
 
 impl fmt::Display for BackgroundProcess {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{} {}\t{}", self.pid, self.state, self.name)
     }
 }
@@ -292,7 +292,9 @@ impl<'a> Shell<'a> {
             // signal, the status of that process will be communicated back. To
             // avoid consuming CPU cycles, we wait 25 ms between polls.
             match self.foreground_signals.was_processed() {
-                Some(BackgroundResult::Status(stat)) => break Status::from_exit_code(stat as i32),
+                Some(BackgroundResult::Status(stat)) => {
+                    break Status::from_exit_code(i32::from(stat))
+                }
                 Some(BackgroundResult::Errored) => break Status::TERMINATED,
                 None => sleep(Duration::from_millis(25)),
             }
diff --git a/src/lib/shell/pipe_exec/mod.rs b/src/lib/shell/pipe_exec/mod.rs
index 60e76dd631528c658f55ed7d567f3cf9d10a2359..016601c476a6915bb9c82fe04fed28641f784cd2 100644
--- a/src/lib/shell/pipe_exec/mod.rs
+++ b/src/lib/shell/pipe_exec/mod.rs
@@ -28,6 +28,7 @@ use crate::{
     parser::pipelines::{Input, PipeItem, PipeType, Pipeline, RedirectFrom, Redirection},
     sys,
 };
+use err_derive::Error;
 use smallvec::SmallVec;
 use std::{
     fmt,
@@ -442,7 +443,7 @@ impl<'b> Shell<'b> {
                 let (mut pgid, mut last_pid, mut current_pid) = (0, 0, 0);
 
                 // Append jobs until all piped jobs are running
-                while let Some((mut child, ckind)) = commands.next() {
+                for (mut child, ckind) in commands {
                     // Keep a reference to the FD to keep them open
                     let mut ext_stdio_pipes: Option<Vec<File>> = None;
 
@@ -531,8 +532,8 @@ impl<'b> Shell<'b> {
 }
 
 fn spawn_proc(
-    shell: &mut Shell,
-    cmd: RefinedJob,
+    shell: &mut Shell<'_>,
+    cmd: RefinedJob<'_>,
     redirection: RedirectFrom,
     block_child: bool,
     last_pid: &mut u32,
diff --git a/src/lib/shell/status.rs b/src/lib/shell/status.rs
index 70cc8ed002a50daa9d06613de060518b83042173..dba11d8e7217359543da446570da64bcfd4fd778 100644
--- a/src/lib/shell/status.rs
+++ b/src/lib/shell/status.rs
@@ -24,11 +24,11 @@ impl Status {
         Status(1)
     }
 
-    pub fn is_success(&self) -> bool { self.0 == 0 }
+    pub fn is_success(self) -> bool { self.0 == 0 }
 
-    pub fn is_failure(&self) -> bool { self.0 != 0 }
+    pub fn is_failure(self) -> bool { self.0 != 0 }
 
-    pub fn as_os_code(&self) -> i32 { self.0 }
+    pub fn as_os_code(self) -> i32 { self.0 }
 
     pub fn toggle(&mut self) { self.0 = if self.is_success() { 1 } else { 0 }; }
 }
diff --git a/src/lib/shell/variables/math.rs b/src/lib/shell/variables/math.rs
index 2b3acfbb2a2bc996824d8077468221a1ef192ad5..20603e6e1da37b114ae8ffddf1c866d5e7ff822c 100644
--- a/src/lib/shell/variables/math.rs
+++ b/src/lib/shell/variables/math.rs
@@ -52,7 +52,7 @@ macro_rules! math {
         impl<'a, 'b> $trait<Value<'a>> for &'b Value<'a> {
             type Output = Result<Value<'static>, OpError>;
 
-            fn $fn(self, rhs: Value) -> Self::Output { self.$fn(&rhs) }
+            fn $fn(self, rhs: Value<'_>) -> Self::Output { self.$fn(&rhs) }
         }
 
         impl<'a, 'b> $trait<i128> for &'b Value<'a> {
@@ -79,7 +79,7 @@ macro_rules! math {
                     Value::Array(lhs) => lhs
                         .iter()
                         .map(|el| el.$fn(rhs))
-                        .collect::<Result<types::Array, _>>()
+                        .collect::<Result<types::Array<'_>, _>>()
                         .map(Value::Array),
                     _ => Err(OpError::TypeError),
                 }
@@ -98,7 +98,7 @@ macro_rules! math {
                     Value::Array(lhs) => lhs
                         .iter()
                         .map(|el| el.$fn(rhs))
-                        .collect::<Result<types::Array, _>>()
+                        .collect::<Result<types::Array<'_>, _>>()
                         .map(Value::Array),
                     _ => Err(OpError::TypeError),
                 }
diff --git a/src/lib/shell/variables/mod.rs b/src/lib/shell/variables/mod.rs
index 9c610e94292740e4870fedd925229a161b32685e..7d8a1caf201bf12a8757687fef68eda4cec12341 100644
--- a/src/lib/shell/variables/mod.rs
+++ b/src/lib/shell/variables/mod.rs
@@ -105,7 +105,7 @@ value_from_type!(bmap: types::BTreeMap<'a> => BTreeMap(bmap));
 value_from_type!(function: Function<'a> => Function(function));
 
 impl<'a> fmt::Display for Value<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             Value::Str(ref str_) => write!(f, "{}", str_),
             Value::Alias(ref alias) => write!(f, "{}", **alias),
@@ -146,7 +146,7 @@ impl<'a> Variables<'a> {
         })
     }
 
-    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Function)> {
+    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Function<'a>)> {
         self.0.scopes().rev().flat_map(|map| {
             map.iter().filter_map(|(key, val)| {
                 if let Value::Function(val) = val {
@@ -158,7 +158,7 @@ impl<'a> Variables<'a> {
         })
     }
 
-    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array)> {
+    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array<'a>)> {
         self.0.scopes().rev().flat_map(|map| {
             map.iter().filter_map(
                 |(key, val)| {
@@ -326,7 +326,7 @@ impl<'a> Variables<'a> {
 
 impl<'a> Default for Variables<'a> {
     fn default() -> Self {
-        let mut map: Scopes<types::Str, Value> = Scopes::with_capacity(64);
+        let mut map: Scopes<types::Str, Value<'a>> = Scopes::with_capacity(64);
         map.set("DIRECTORY_STACK_SIZE", "1000");
         map.set("HISTORY_SIZE", "1000");
         map.set("HISTFILE_SIZE", "100000");
diff --git a/src/lib/shell/variables/trait_test.rs b/src/lib/shell/variables/trait_test.rs
index a1d380d86f3b746ec72d95af5ac8e915023fa26b..1e7b2008f881eb6e4977158165d86a818865782e 100644
--- a/src/lib/shell/variables/trait_test.rs
+++ b/src/lib/shell/variables/trait_test.rs
@@ -425,7 +425,7 @@ fn euc_var_var_array() {
 fn filter_var() {
     let mut a = Value::Array(array![types::Str::from(".16"), types::Str::from("1")]);
     let b = Value::Str("1".into());
-    Option::<&mut types::Array>::from(&mut a).unwrap().retain(|c| c != &b);
+    Option::<&mut types::Array<'_>>::from(&mut a).unwrap().retain(|c| c != &b);
     assert_eq!(a, Value::Array(array![types::Str::from(".16")]));
 }
 
@@ -433,7 +433,7 @@ fn filter_var() {
 fn filter_var_float() {
     let mut a = Value::Array(array![types::Str::from(".16"), types::Str::from("1")]);
     let b = Value::Str("0.16".into());
-    Option::<&mut types::Array>::from(&mut a).unwrap().retain(|c| c != &b);
+    Option::<&mut types::Array<'_>>::from(&mut a).unwrap().retain(|c| c != &b);
     assert_eq!(a, Value::Array(array![types::Str::from(".16"), types::Str::from("1")]));
 }
 
diff --git a/src/main.rs b/src/main.rs
index 6e4cd7d3a9b4f524835e95fc52c78e8ba46d0763..85650730c63160f55b7e01a5db2427d4143f34f9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,8 +1,8 @@
-extern crate ion_sys as sys;
 mod binary;
 
 use self::binary::{InteractiveBinary, MAN_ION};
 use ion_shell::{Shell, Value};
+use ion_sys as sys;
 use liner::KeyBindings;
 use std::{
     alloc::System,