diff --git a/lalrpop/src/grammar/free_variables.rs b/lalrpop/src/grammar/free_variables.rs index f6b18ed..aaa5cd4 100644 --- a/lalrpop/src/grammar/free_variables.rs +++ b/lalrpop/src/grammar/free_variables.rs @@ -1,5 +1,6 @@ use grammar::parse_tree::{self, TypeParameter}; use grammar::repr; +use std::iter; /// Finds the set of "free variables" in something -- that is, the /// type/lifetime parameters that appear and are not bound. For @@ -19,9 +20,7 @@ impl FreeVariables for Option { impl FreeVariables for Vec { fn free_variables(&self) -> Vec { - self.into_iter() - .flat_map(|e| e.free_variables()) - .collect() + self.into_iter().flat_map(|e| e.free_variables()).collect() } } @@ -31,7 +30,8 @@ impl FreeVariables for repr::TypeRepr { repr::TypeRepr::Tuple(tys) => tys.free_variables(), repr::TypeRepr::Nominal(data) => data.free_variables(), repr::TypeRepr::Associated { - type_parameter, id: _ + type_parameter, + id: _, } => vec![TypeParameter::Id(type_parameter.clone())], repr::TypeRepr::Lifetime(l) => vec![TypeParameter::Lifetime(l.clone())], repr::TypeRepr::Ref { @@ -69,3 +69,61 @@ impl FreeVariables for repr::NominalTypeRepr { .collect() } } + +impl FreeVariables for parse_tree::WhereClause { + fn free_variables(&self) -> Vec { + match self { + parse_tree::WhereClause::Lifetime { lifetime, bounds } => + iter::once(TypeParameter::Lifetime(lifetime.clone())) + .chain(bounds.iter().map(|l| TypeParameter::Lifetime(l.clone()))) + .collect(), + + parse_tree::WhereClause::Type { forall, ty, bounds } => ty + .free_variables() + .into_iter() + .chain(bounds.free_variables()) + .filter(|tp| !forall.contains(tp)) + .collect(), + } + } +} + +impl FreeVariables for parse_tree::TypeBoundParameter { + fn free_variables(&self) -> Vec { + match self { + parse_tree::TypeBoundParameter::Lifetime(l) => vec![TypeParameter::Lifetime(l.clone())], + parse_tree::TypeBoundParameter::TypeParameter(t) => t.free_variables(), + parse_tree::TypeBoundParameter::Associated(..) => vec![], + } + } +} + +impl FreeVariables for parse_tree::TypeBound { + fn free_variables(&self) -> Vec { + match self { + parse_tree::TypeBound::Lifetime(l) => vec![TypeParameter::Lifetime(l.clone())], + parse_tree::TypeBound::Fn { + forall, + path, + parameters, + ret, + } => path + .free_variables() + .into_iter() + .chain(parameters.free_variables()) + .chain(ret.free_variables()) + .filter(|tp| !forall.contains(tp)) + .collect(), + parse_tree::TypeBound::Trait { + forall, + path, + parameters, + } => path + .free_variables() + .into_iter() + .chain(parameters.free_variables()) + .filter(|tp| !forall.contains(tp)) + .collect(), + } + } +} diff --git a/lalrpop/src/lr1/codegen/ascent.rs b/lalrpop/src/lr1/codegen/ascent.rs index 248d86b..cb5f876 100644 --- a/lalrpop/src/lr1/codegen/ascent.rs +++ b/lalrpop/src/lr1/codegen/ascent.rs @@ -145,17 +145,16 @@ impl<'ascent, 'grammar, W: Write> .cloned() .collect(); - let mut referenced_where_clauses = Set::new(); - for wc in &grammar.where_clauses { - wc.map(|ty| { - if ty.free_variables() + let referenced_where_clauses: Set<_> = grammar + .where_clauses + .iter() + .filter(|wc| { + wc.free_variables() .iter() .any(|p| nonterminal_type_params.contains(p)) - { - referenced_where_clauses.insert(wc.clone()); - } - }); - } + }) + .cloned() + .collect(); let nonterminal_where_clauses: Vec<_> = grammar .where_clauses @@ -547,7 +546,7 @@ impl<'ascent, 'grammar, W: Write> vec![format!( "{}TOKENS: Iterator>", self.prefix, triple_type, iter_error_type - ),], + )], None, true, // include grammar parameters fn_args, diff --git a/lalrpop/src/lr1/codegen/parse_table.rs b/lalrpop/src/lr1/codegen/parse_table.rs index adb36d0..9e1fc48 100644 --- a/lalrpop/src/lr1/codegen/parse_table.rs +++ b/lalrpop/src/lr1/codegen/parse_table.rs @@ -319,17 +319,16 @@ impl<'ascent, 'grammar, W: Write> CodeGenerator<'ascent, 'grammar, W, TableDrive .cloned() .collect(); - let mut referenced_where_clauses = Set::new(); - for wc in &grammar.where_clauses { - wc.map(|ty| { - if ty.free_variables() + let referenced_where_clauses: Set<_> = grammar + .where_clauses + .iter() + .filter(|wc| { + wc.free_variables() .iter() .any(|p| symbol_type_params.contains(p)) - { - referenced_where_clauses.insert(wc.clone()); - } - }); - } + }) + .cloned() + .collect(); let symbol_where_clauses: Vec<_> = grammar .where_clauses