140 likes | 245 Views
S EMINAL : Searching for Type-Error Messages. Benjamin Lerner, Dan Grossman, Craig Chambers University of Washington. # let map2 f aList bList = List.map (fun (a, b) -> f a b) (List.combine aList bList);;
E N D
SEMINAL: Searching for Type-Error Messages Benjamin Lerner, Dan Grossman, Craig Chambers University of Washington
# let map2 f aList bList = List.map (fun (a, b) -> f a b) (List.combine aList bList);; val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun> # map2 (fun (x, y) -> x + y) [1;2;3] [4;5;6];; This expression has type int but is here used with type 'a -> 'b Try replacing fun (x, y) -> x + y with fun x y -> x + y Example: ML Curried functions
template <class A, class B> list<B> map(B (*f)(A), list<A> aList); template <class A> list<list<A> > transpose( list<list<A> > aMatrix); map(ptr_fun(transpose<int>), myIntMatrixList); temp.cpp:42: error: no matching function for call to map(std::pointer_to_unary_function<std::list<std::list<int, std::allocator<int> >, std::allocator<std::list<int, std::allocator<int> > > >, std::list<std::list<int, std::allocator<int> >, std::allocator<std::list<int, std::allocator<int> > > > >, std::list<std::list<std::list<int, std::allocator<int> >, std::allocator<std::list<int, std::allocator<int> > > >, std::allocator<std::list<std::list<int, std::allocator<int> >, std::allocator<std::list<int, std::allocator<int> > > > > >&) Try replacing ptr_fun(transpose<int>) with &(transpose<int>) Example: C++ Template Usage temp.cpp:42: error: No match for map( pointer_to_unary_function<list<list<int> >, list<list<int> > >, list<list<list<int> > > &)
What went right? • Easy polymorphic functions • map2 works for any kind of list • transpose works for any kind of matrix • Type inference • Writing types manually is tedious • Type-inference makes generic programming easier • …Even more powerful type-systems need type inference even more.
What went wrong? These type-error messages… • …are not local (particularly ML) • Symptoms <> Problems • …are not intuitive (particularly C++) • Very lengthy types are hard to read • …are not descriptive • Location + types <> Solution • …are due to type inference/instantiation
Related work • Instrument the type-checker, making its messages more informative • But that leads to tight coupling • Implementing a TC is easy • Implementing a production TC is hard • Adding good error messages makes it even harder • Interferes with easy revision or extension of TC • Error messages in TC adds to compiler’s trusted computing base See paper for citations
Our Approach, in one slide • Treats type checker as oracle • Makes no assumptions about the type system • Note: no dependence on how TC works • Tries many variations on program, see which ones work • Must do this carefully – there are too many! • Note: “Variant works” <> “Variant is right” • Ranks successful suggestions, presents results to programmer
Architecture – Searcher Defines the strategy for looking for fixes: • Look for single AST subtree to remove that will make problem “go away” • Replace subtree with “wildcards” • Interesting subtrees guide the search • If removing a subtree worked, try its children … • Often improves on existing messages’ locations • Rely on Enumerator’s suggestions for more detail
Architecture – Enumerator Defines the fixes to be tried: • Try custom attempts for each type of AST node • E.g. Function applications break differently than if-then expressions • Enumeration is term-directed • A function of AST nodes only • More enumerated attempts better messages • Called by Searcher when needed
Architecture – Ranker Defines the relative merit of successful fixes: • Search can produce too many results • Not all results are helpful to user • E.g. “Replace whole program with ”! • Use heuristics to filter and sort messages • “Smallest fixes are best” • “Currying a function is better than deleting it” • Simple heuristics seem sufficient
Preliminary results • ML prototype: on ocaml-3.08.4 • Mostly complete • C++ prototype: on Eclipse 3.2, CDT 3.1, gcc 3.4.4 • Active work • Ongoing analysis of ~2K ML files collected from students • Group messages as “good”, “misleading”, “bad” • Check if message precisely locates problem • Check if message approximates student’s actual fix • Results: • Very good precision on small test cases • Good precision on real, large problems • Most poor results stem from common cause
Errors may be widely separated Least common parent is too big Idea: ignore most code, focus on one error Triage:Trade “complete”for “small” Dealing with multiple errors
Conclusions • Searching for repairs yields intuitively helpful messages • SEMINAL decouples type-checker from error-message generator • Simpler TC architecture • Smaller trusted computing base • It’s a win-win scenario!