Merge pull request #259 from nikomatsakis/issue-249

avoid out-of-bounds error in error classification
This commit is contained in:
Niko Matsakis 2017-08-30 06:25:24 -04:00 committed by GitHub
commit 4176ff6313
4 changed files with 44 additions and 2 deletions

View File

@ -444,6 +444,12 @@ impl<'cx, 'grammar> ErrorReportingCx<'cx, 'grammar> {
action_examples.sort_by(|e, f| e.symbols.len().cmp(&f.symbols.len()));
reduce_examples.sort_by(|e, f| e.symbols.len().cmp(&f.symbols.len()));
// This really shouldn't happen, but if we've failed to come
// up with examples, then report a "naive" error.
if action_examples.is_empty() || reduce_examples.is_empty() {
return ConflictClassification::Naive;
}
if let Some(classification) = self.try_classify_ambiguity(conflict,
&action_examples,
&reduce_examples) {
@ -532,6 +538,9 @@ impl<'cx, 'grammar> ErrorReportingCx<'cx, 'grammar> {
return None;
}
debug!("try_classify_question: action_examples={:?}", action_examples);
debug!("try_classify_question: reduce_examples={:?}", reduce_examples);
let nt = conflict.production.nonterminal;
let nt_productions = self.grammar.productions_for(nt);
if nt_productions.len() == 2 {

View File

@ -148,3 +148,25 @@ Ident = r#"[a-zA-Z][a-zA-Z0-9]*"#;
r => panic!("wrong classification {:#?}", r)
}
}
/// This example used to cause an out-of-bounds error.
#[test]
fn issue_249() {
let _tls = Tls::test();
let grammar = normalized_grammar(r##"
grammar;
pub Func = StructDecl* VarDecl*;
StructDecl = "<" StructParameter* ">";
StructParameter = "may_dangle"?;
VarDecl = "let";
"##);
let _lr1_tls = Lr1Tls::install(grammar.terminals.clone());
let err = build_states(&grammar, nt("Func")).unwrap_err();
let mut cx = ErrorReportingCx::new(&grammar, &err.states, &err.conflicts);
let conflicts = super::token_conflicts(&err.conflicts);
for conflict in &conflicts {
println!("conflict={:?}", conflict);
cx.classify(conflict);
}
}

View File

@ -60,6 +60,8 @@ impl<'grammar> LaneTableConstruct<'grammar> {
// We failed because of irreconcilable conflicts
// somewhere. Just compute the conflicts from the final set of
// states.
debug!("construct: failed to resolve inconsistencies in state {:#?}",
states[i]);
let conflicts: Vec<Conflict<'grammar, TokenSet>> =
states.iter()
.flat_map(|s| Lookahead::conflicts(&s))
@ -167,7 +169,10 @@ impl<'grammar> LaneTableConstruct<'grammar> {
for beachhead_state in beachhead_states {
match merge.start(beachhead_state) {
Ok(()) => { }
Err((source, _)) => return Err(source),
Err((source, _)) => {
debug!("resolve_inconsistencies: failed to merge, source={:?}", source);
return Err(source);
}
}
}
merge.patch_target_starts(&actions);

View File

@ -118,13 +118,19 @@ impl<'grammar> LaneTable<'grammar> {
pub fn rows(&self) -> Result<Map<StateIndex, ContextSet>, StateIndex> {
let mut map = Map::new();
for (&(state_index, conflict_index), token_set) in &self.lookaheads {
debug!("rows: inserting state_index={:?} conflict_index={:?} token_set={:?}",
state_index, conflict_index, token_set);
match {
map.entry(state_index)
.or_insert_with(|| ContextSet::new(self.conflicts))
.insert(conflict_index, token_set)
} {
Ok(_changed) => { }
Err(OverlappingLookahead) => return Err(state_index)
Err(OverlappingLookahead) => {
debug!("rows: intra-row conflict inserting state_index={:?} conflict_index={:?} token_set={:?}",
state_index, conflict_index, token_set);
return Err(state_index);
}
}
}