Make package:html strong clean

R=jmesserly@google.com

Review URL: https://codereview.chromium.org//1971923002 .
diff --git a/.analysis_options b/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4dbea39..3320989 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,14 @@
 This file contains highlights of what changes on each version of the html
 package.
 
+## 0.13.0
+
+ * **BREAKING** Fix all [strong mode][] errors and warnings.
+   This involved adding more precise types on some public APIs, which is why it
+   may break users.
+
+[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+
 #### Pub version 0.12.2+2
   * Support `csslib` versions `0.13.x`.
   
diff --git a/lib/dom.dart b/lib/dom.dart
index 9e64759..63182f6 100644
--- a/lib/dom.dart
+++ b/lib/dom.dart
@@ -742,16 +742,17 @@
 
   // TODO(jmesserly): These aren't implemented in DOM _NodeListImpl, see
   // http://code.google.com/p/dart/issues/detail?id=5371
-  void setRange(int start, int rangeLength, List<Node> from,
+  void setRange(int start, int rangeLength, Iterable<Node> from,
       [int startFrom = 0]) {
-    if (from is NodeList) {
+    List<Node> from_ = from as List<Node>;
+    if (from_ is NodeList) {
       // Note: this is presumed to make a copy
-      from = from.sublist(startFrom, startFrom + rangeLength);
+      from_ = from_.sublist(startFrom, startFrom + rangeLength);
     }
     // Note: see comment in [addAll]. We need to be careful about the order of
     // operations if [from] is also a NodeList.
     for (int i = rangeLength - 1; i >= 0; i--) {
-      this[start + i] = from[startFrom + i];
+      this[start + i] = from_[startFrom + i];
     }
   }
 
@@ -765,14 +766,14 @@
     super.removeRange(start, rangeLength);
   }
 
-  void removeWhere(bool test(Element e)) {
+  void removeWhere(bool test(Node e)) {
     for (var node in where(test)) {
       node.parentNode = null;
     }
     super.removeWhere(test);
   }
 
-  void retainWhere(bool test(Element e)) {
+  void retainWhere(bool test(Node e)) {
     for (var node in where((n) => !test(n))) {
       node.parentNode = null;
     }
@@ -786,11 +787,11 @@
     super.insertAll(index, list);
   }
 
-  _flattenDocFragments(Iterable<Node> collection) {
+  List<Node> _flattenDocFragments(Iterable<Node> collection) {
     // Note: this function serves two purposes:
     //  * it flattens document fragments
     //  * it creates a copy of [collections] when `collection is NodeList`.
-    var result = [];
+    var result = <Node>[];
     for (var node in collection) {
       if (node is DocumentFragment) {
         result.addAll(node.nodes);
@@ -860,7 +861,7 @@
     }
   }
 
-  bool contains(Element element) {
+  bool contains(Object element) {
     return element is Element && _childNodes.contains(element);
   }
 
@@ -901,9 +902,10 @@
     return result;
   }
 
-  Iterable map(f(Element element)) => _filtered.map(f);
+  Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(Element element)) => _filtered.map(f);
   Iterable<Element> where(bool f(Element element)) => _filtered.where(f);
-  Iterable expand(Iterable f(Element element)) => _filtered.expand(f);
+  Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(Element element)) =>
+      _filtered.expand(f);
 
   void insert(int index, Element value) {
     _childNodes.insert(index, value);
@@ -935,8 +937,8 @@
     return _filtered.reduce(combine);
   }
 
-  dynamic fold(dynamic initialValue,
-      dynamic combine(dynamic previousValue, Element element)) {
+  dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+      dynamic/*=T*/ combine(var/*=T*/ previousValue, Element element)) {
     return _filtered.fold(initialValue, combine);
   }
 
@@ -968,10 +970,14 @@
   List<Element> sublist(int start, [int end]) => _filtered.sublist(start, end);
   Iterable<Element> getRange(int start, int end) =>
       _filtered.getRange(start, end);
-  int indexOf(Element element, [int start = 0]) =>
+  // TODO(sigmund): this should be typed Element, but we currently run into a
+  // bug where ListMixin<E>.indexOf() expects Object as the argument.
+  int indexOf(element, [int start = 0]) =>
       _filtered.indexOf(element, start);
 
-  int lastIndexOf(Element element, [int start = null]) {
+  // TODO(sigmund): this should be typed Element, but we currently run into a
+  // bug where ListMixin<E>.lastIndexOf() expects Object as the argument.
+  int lastIndexOf(element, [int start = null]) {
     if (start == null) start = length - 1;
     return _filtered.lastIndexOf(element, start);
   }
diff --git a/lib/parser.dart b/lib/parser.dart
index dc95941..0575b3d 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -210,7 +210,7 @@
       try {
         mainLoop();
         break;
-      } on ReparseException catch (e) {
+      } on ReparseException catch (_) {
         // Note: this happens if we start parsing but the character encoding
         // changes. So we should only need to restart very early in the parse.
         reset();
@@ -819,7 +819,8 @@
 
   // helper methods
   void insertHtmlElement() {
-    tree.insertRoot(new StartTagToken("html", data: {}));
+    tree.insertRoot(new StartTagToken("html",
+        data: new LinkedHashMap<dynamic, String>()));
     parser.phase = parser._beforeHeadPhase;
   }
 
@@ -875,7 +876,8 @@
       case 'html':
         return startTagHtml(token);
       case 'head':
-        return startTagHead(token);
+        startTagHead(token);
+        return null;
       default:
         return startTagOther(token);
     }
@@ -889,12 +891,14 @@
       case "br":
         return endTagImplyHead(token);
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
   bool processEOF() {
-    startTagHead(new StartTagToken("head", data: {}));
+    startTagHead(new StartTagToken("head",
+        data: new LinkedHashMap<dynamic, String>()));
     return true;
   }
 
@@ -903,7 +907,8 @@
   }
 
   Token processCharacters(CharactersToken token) {
-    startTagHead(new StartTagToken("head", data: {}));
+    startTagHead(new StartTagToken("head",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -918,12 +923,14 @@
   }
 
   Token startTagOther(StartTagToken token) {
-    startTagHead(new StartTagToken("head", data: {}));
+    startTagHead(new StartTagToken("head",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
   Token endTagImplyHead(EndTagToken token) {
-    startTagHead(new StartTagToken("head", data: {}));
+    startTagHead(new StartTagToken("head",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -941,23 +948,29 @@
       case "html":
         return startTagHtml(token);
       case "title":
-        return startTagTitle(token);
+        startTagTitle(token);
+        return null;
       case "noscript":
       case "noframes":
       case "style":
-        return startTagNoScriptNoFramesStyle(token);
+        startTagNoScriptNoFramesStyle(token);
+        return null;
       case "script":
-        return startTagScript(token);
+        startTagScript(token);
+        return null;
       case "base":
       case "basefont":
       case "bgsound":
       case "command":
       case "link":
-        return startTagBaseLinkCommand(token);
+        startTagBaseLinkCommand(token);
+        return null;
       case "meta":
-        return startTagMeta(token);
+        startTagMeta(token);
+        return null;
       case "head":
-        return startTagHead(token);
+        startTagHead(token);
+        return null;
       default:
         return startTagOther(token);
     }
@@ -966,13 +979,15 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "head":
-        return endTagHead(token);
+        endTagHead(token);
+        return null;
       case "br":
       case "html":
       case "body":
         return endTagHtmlBodyBr(token);
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -1075,9 +1090,11 @@
       case "html":
         return startTagHtml(token);
       case "body":
-        return startTagBody(token);
+        startTagBody(token);
+        return null;
       case "frameset":
-        return startTagFrameset(token);
+        startTagFrameset(token);
+        return null;
       case "base":
       case "basefont":
       case "bgsound":
@@ -1087,9 +1104,11 @@
       case "script":
       case "style":
       case "title":
-        return startTagFromHead(token);
+        startTagFromHead(token);
+        return null;
       case "head":
-        return startTagHead(token);
+        startTagHead(token);
+        return null;
       default:
         return startTagOther(token);
     }
@@ -1102,7 +1121,8 @@
       case "br":
         return endTagHtmlBodyBr(token);
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -1164,7 +1184,8 @@
   }
 
   void anythingElse() {
-    tree.insertElement(new StartTagToken("body", data: {}));
+    tree.insertElement(new StartTagToken("body",
+        data: new LinkedHashMap<dynamic, String>()));
     parser.phase = parser._inBodyPhase;
     parser.framesetOK = true;
   }
@@ -1195,9 +1216,11 @@
       case "title":
         return startTagProcessInHead(token);
       case "body":
-        return startTagBody(token);
+        startTagBody(token);
+        return null;
       case "frameset":
-        return startTagFrameset(token);
+        startTagFrameset(token);
+        return null;
       case "address":
       case "article":
       case "aside":
@@ -1221,7 +1244,8 @@
       case "section":
       case "summary":
       case "ul":
-        return startTagCloseP(token);
+        startTagCloseP(token);
+        return null;
       // headingElements
       case "h1":
       case "h2":
@@ -1229,20 +1253,26 @@
       case "h4":
       case "h5":
       case "h6":
-        return startTagHeading(token);
+        startTagHeading(token);
+        return null;
       case "pre":
       case "listing":
-        return startTagPreListing(token);
+        startTagPreListing(token);
+        return null;
       case "form":
-        return startTagForm(token);
+        startTagForm(token);
+        return null;
       case "li":
       case "dd":
       case "dt":
-        return startTagListItem(token);
+        startTagListItem(token);
+        return null;
       case "plaintext":
-        return startTagPlaintext(token);
+        startTagPlaintext(token);
+        return null;
       case "a":
-        return startTagA(token);
+        startTagA(token);
+        return null;
       case "b":
       case "big":
       case "code":
@@ -1255,58 +1285,77 @@
       case "strong":
       case "tt":
       case "u":
-        return startTagFormatting(token);
+        startTagFormatting(token);
+        return null;
       case "nobr":
-        return startTagNobr(token);
+        startTagNobr(token);
+        return null;
       case "button":
         return startTagButton(token);
       case "applet":
       case "marquee":
       case "object":
-        return startTagAppletMarqueeObject(token);
+        startTagAppletMarqueeObject(token);
+        return null;
       case "xmp":
-        return startTagXmp(token);
+        startTagXmp(token);
+        return null;
       case "table":
-        return startTagTable(token);
+        startTagTable(token);
+        return null;
       case "area":
       case "br":
       case "embed":
       case "img":
       case "keygen":
       case "wbr":
-        return startTagVoidFormatting(token);
+        startTagVoidFormatting(token);
+        return null;
       case "param":
       case "source":
       case "track":
-        return startTagParamSource(token);
+        startTagParamSource(token);
+        return null;
       case "input":
-        return startTagInput(token);
+        startTagInput(token);
+        return null;
       case "hr":
-        return startTagHr(token);
+        startTagHr(token);
+        return null;
       case "image":
-        return startTagImage(token);
+        startTagImage(token);
+        return null;
       case "isindex":
-        return startTagIsIndex(token);
+        startTagIsIndex(token);
+        return null;
       case "textarea":
-        return startTagTextarea(token);
+        startTagTextarea(token);
+        return null;
       case "iframe":
-        return startTagIFrame(token);
+        startTagIFrame(token);
+        return null;
       case "noembed":
       case "noframes":
       case "noscript":
-        return startTagRawtext(token);
+        startTagRawtext(token);
+        return null;
       case "select":
-        return startTagSelect(token);
+        startTagSelect(token);
+        return null;
       case "rp":
       case "rt":
-        return startTagRpRt(token);
+        startTagRpRt(token);
+        return null;
       case "option":
       case "optgroup":
-        return startTagOpt(token);
+        startTagOpt(token);
+        return null;
       case "math":
-        return startTagMath(token);
+        startTagMath(token);
+        return null;
       case "svg":
-        return startTagSvg(token);
+        startTagSvg(token);
+        return null;
       case "caption":
       case "col":
       case "colgroup":
@@ -1318,7 +1367,8 @@
       case "th":
       case "thead":
       case "tr":
-        return startTagMisplaced(token);
+        startTagMisplaced(token);
+        return null;
       default:
         return startTagOther(token);
     }
@@ -1327,7 +1377,8 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "body":
-        return endTagBody(token);
+        endTagBody(token);
+        return null;
       case "html":
         return endTagHtml(token);
       case "address":
@@ -1353,15 +1404,19 @@
       case "section":
       case "summary":
       case "ul":
-        return endTagBlock(token);
+        endTagBlock(token);
+        return null;
       case "form":
-        return endTagForm(token);
+        endTagForm(token);
+        return null;
       case "p":
-        return endTagP(token);
+        endTagP(token);
+        return null;
       case "dd":
       case "dt":
       case "li":
-        return endTagListItem(token);
+        endTagListItem(token);
+        return null;
       // headingElements
       case "h1":
       case "h2":
@@ -1369,7 +1424,8 @@
       case "h4":
       case "h5":
       case "h6":
-        return endTagHeading(token);
+        endTagHeading(token);
+        return null;
       case "a":
       case "b":
       case "big":
@@ -1384,15 +1440,19 @@
       case "strong":
       case "tt":
       case "u":
-        return endTagFormatting(token);
+        endTagFormatting(token);
+        return null;
       case "applet":
       case "marquee":
       case "object":
-        return endTagAppletMarqueeObject(token);
+        endTagAppletMarqueeObject(token);
+        return null;
       case "br":
-        return endTagBr(token);
+        endTagBr(token);
+        return null;
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -1733,28 +1793,31 @@
     if (tree.formPointer != null) {
       return;
     }
-    var formAttrs = {};
+    var formAttrs = new LinkedHashMap<dynamic, String>();
     var dataAction = token.data["action"];
     if (dataAction != null) {
       formAttrs["action"] = dataAction;
     }
     processStartTag(new StartTagToken("form", data: formAttrs));
-    processStartTag(new StartTagToken("hr", data: {}));
-    processStartTag(new StartTagToken("label", data: {}));
+    processStartTag(new StartTagToken("hr",
+        data: new LinkedHashMap<dynamic, String>()));
+    processStartTag(new StartTagToken("label",
+        data: new LinkedHashMap<dynamic, String>()));
     // XXX Localization ...
     var prompt = token.data["prompt"];
     if (prompt == null) {
       prompt = "This is a searchable index. Enter search keywords: ";
     }
     processCharacters(new CharactersToken(prompt));
-    var attributes = new LinkedHashMap.from(token.data);
+    var attributes = new LinkedHashMap<dynamic, String>.from(token.data);
     attributes.remove('action');
     attributes.remove('prompt');
     attributes["name"] = "isindex";
     processStartTag(new StartTagToken(
         "input", data: attributes, selfClosing: token.selfClosing));
     processEndTag(new EndTagToken("label"));
-    processStartTag(new StartTagToken("hr", data: {}));
+    processStartTag(new StartTagToken("hr",
+        data: new LinkedHashMap<dynamic, String>()));
     processEndTag(new EndTagToken("form"));
   }
 
@@ -1857,7 +1920,8 @@
 
   void endTagP(EndTagToken token) {
     if (!tree.elementInScope("p", variant: "button")) {
-      startTagCloseP(new StartTagToken("p", data: {}));
+      startTagCloseP(new StartTagToken("p",
+          data: new LinkedHashMap<dynamic, String>()));
       parser.parseError(token.span, "unexpected-end-tag", {"name": "p"});
       endTagP(new EndTagToken("p"));
     } else {
@@ -1994,7 +2058,7 @@
   }
 
   /// The much-feared adoption agency algorithm.
-  endTagFormatting(EndTagToken token) {
+  void endTagFormatting(EndTagToken token) {
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#adoptionAgency
     // TODO(jmesserly): the comments here don't match the numbered steps in the
     // updated spec. This needs a pass over it to verify that it still matches.
@@ -2164,7 +2228,8 @@
       "newName": "br element"
     });
     tree.reconstructActiveFormattingElements();
-    tree.insertElement(new StartTagToken("br", data: {}));
+    tree.insertElement(new StartTagToken("br",
+        data: new LinkedHashMap<dynamic, String>()));
     tree.openElements.removeLast();
   }
 
@@ -2199,8 +2264,11 @@
   }
 
   processEndTag(EndTagToken token) {
-    if (token.name == 'script') return endTagScript(token);
-    return endTagOther(token);
+    if (token.name == 'script') {
+      endTagScript(token);
+      return null;
+    }
+    endTagOther(token);
   }
 
   Token processCharacters(CharactersToken token) {
@@ -2240,15 +2308,18 @@
       case "html":
         return startTagHtml(token);
       case "caption":
-        return startTagCaption(token);
+        startTagCaption(token);
+        return null;
       case "colgroup":
-        return startTagColgroup(token);
+        startTagColgroup(token);
+        return null;
       case "col":
         return startTagCol(token);
       case "tbody":
       case "tfoot":
       case "thead":
-        return startTagRowGroup(token);
+        startTagRowGroup(token);
+        return null;
       case "td":
       case "th":
       case "tr":
@@ -2259,18 +2330,22 @@
       case "script":
         return startTagStyleScript(token);
       case "input":
-        return startTagInput(token);
+        startTagInput(token);
+        return null;
       case "form":
-        return startTagForm(token);
+        startTagForm(token);
+        return null;
       default:
-        return startTagOther(token);
+        startTagOther(token);
+        return null;
     }
   }
 
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "table":
-        return endTagTable(token);
+        endTagTable(token);
+        return null;
       case "body":
       case "caption":
       case "col":
@@ -2282,9 +2357,11 @@
       case "th":
       case "thead":
       case "tr":
-        return endTagIgnore(token);
+        endTagIgnore(token);
+        return null;
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -2350,7 +2427,8 @@
   }
 
   Token startTagCol(StartTagToken token) {
-    startTagColgroup(new StartTagToken("colgroup", data: {}));
+    startTagColgroup(new StartTagToken("colgroup",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -2361,7 +2439,8 @@
   }
 
   Token startTagImplyTbody(StartTagToken token) {
-    startTagRowGroup(new StartTagToken("tbody", data: {}));
+    startTagRowGroup(new StartTagToken("tbody",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -2542,7 +2621,8 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "caption":
-        return endTagCaption(token);
+        endTagCaption(token);
+        return null;
       case "table":
         return endTagTable(token);
       case "body":
@@ -2555,7 +2635,8 @@
       case "th":
       case "thead":
       case "tr":
-        return endTagIgnore(token);
+        endTagIgnore(token);
+        return null;
       default:
         return endTagOther(token);
     }
@@ -2641,7 +2722,8 @@
       case "html":
         return startTagHtml(token);
       case "col":
-        return startTagCol(token);
+        startTagCol(token);
+        return null;
       default:
         return startTagOther(token);
     }
@@ -2650,9 +2732,11 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "colgroup":
-        return endTagColgroup(token);
+        endTagColgroup(token);
+        return null;
       case "col":
-        return endTagCol(token);
+        endTagCol(token);
+        return null;
       default:
         return endTagOther(token);
     }
@@ -2722,7 +2806,8 @@
       case "html":
         return startTagHtml(token);
       case "tr":
-        return startTagTr(token);
+        startTagTr(token);
+        return null;
       case "td":
       case "th":
         return startTagTableCell(token);
@@ -2743,7 +2828,8 @@
       case "tbody":
       case "tfoot":
       case "thead":
-        return endTagTableRowGroup(token);
+        endTagTableRowGroup(token);
+        return null;
       case "table":
         return endTagTable(token);
       case "body":
@@ -2754,7 +2840,8 @@
       case "td":
       case "th":
       case "tr":
-        return endTagIgnore(token);
+        endTagIgnore(token);
+        return null;
       default:
         return endTagOther(token);
     }
@@ -2796,7 +2883,8 @@
   Token startTagTableCell(StartTagToken token) {
     parser.parseError(
         token.span, "unexpected-cell-in-table-body", {"name": token.name});
-    startTagTr(new StartTagToken("tr", data: {}));
+    startTagTr(new StartTagToken("tr",
+        data: new LinkedHashMap<dynamic, String>()));
     return token;
   }
 
@@ -2854,7 +2942,8 @@
         return startTagHtml(token);
       case "td":
       case "th":
-        return startTagTableCell(token);
+        startTagTableCell(token);
+        return null;
       case "caption":
       case "col":
       case "colgroup":
@@ -2871,7 +2960,8 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "tr":
-        return endTagTr(token);
+        endTagTr(token);
+        return null;
       case "table":
         return endTagTable(token);
       case "tbody":
@@ -2885,7 +2975,8 @@
       case "html":
       case "td":
       case "th":
-        return endTagIgnore(token);
+        endTagIgnore(token);
+        return null;
       default:
         return endTagOther(token);
     }
@@ -3009,13 +3100,15 @@
     switch (token.name) {
       case "td":
       case "th":
-        return endTagTableCell(token);
+        endTagTableCell(token);
+        return null;
       case "body":
       case "caption":
       case "col":
       case "colgroup":
       case "html":
-        return endTagIgnore(token);
+        endTagIgnore(token);
+        return null;
       case "table":
       case "tbody":
       case "tfoot":
@@ -3109,11 +3202,14 @@
       case "html":
         return startTagHtml(token);
       case "option":
-        return startTagOption(token);
+        startTagOption(token);
+        return null;
       case "optgroup":
-        return startTagOptgroup(token);
+        startTagOptgroup(token);
+        return null;
       case "select":
-        return startTagSelect(token);
+        startTagSelect(token);
+        return null;
       case "input":
       case "keygen":
       case "textarea":
@@ -3128,13 +3224,17 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "option":
-        return endTagOption(token);
+        endTagOption(token);
+        return null;
       case "optgroup":
-        return endTagOptgroup(token);
+        endTagOptgroup(token);
+        return null;
       case "select":
-        return endTagSelect(token);
+        endTagSelect(token);
+        return null;
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -3504,7 +3604,10 @@
   }
 
   processEndTag(EndTagToken token) {
-    if (token.name == "html") return endTagHtml(token);
+    if (token.name == "html") {
+      endTagHtml(token);
+      return null;
+    }
     return endTagOther(token);
   }
 
@@ -3566,9 +3669,11 @@
       case "html":
         return startTagHtml(token);
       case "frameset":
-        return startTagFrameset(token);
+        startTagFrameset(token);
+        return null;
       case "frame":
-        return startTagFrame(token);
+        startTagFrame(token);
+        return null;
       case "noframes":
         return startTagNoframes(token);
       default:
@@ -3579,9 +3684,11 @@
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "frameset":
-        return endTagFrameset(token);
+        endTagFrameset(token);
+        return null;
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -3653,16 +3760,19 @@
       case "noframes":
         return startTagNoframes(token);
       default:
-        return startTagOther(token);
+        startTagOther(token);
+        return null;
     }
   }
 
   processEndTag(EndTagToken token) {
     switch (token.name) {
       case "html":
-        return endTagHtml(token);
+        endTagHtml(token);
+        return null;
       default:
-        return endTagOther(token);
+        endTagOther(token);
+        return null;
     }
   }
 
@@ -3748,7 +3858,8 @@
       case "noframes":
         return startTagNoFrames(token);
       default:
-        return startTagOther(token);
+        startTagOther(token);
+        return null;
     }
   }
 
diff --git a/lib/src/css_class_set.dart b/lib/src/css_class_set.dart
index 2e131a5..c7927b8 100644
--- a/lib/src/css_class_set.dart
+++ b/lib/src/css_class_set.dart
@@ -55,7 +55,7 @@
    * This is the Dart equivalent of jQuery's
    * [hasClass](http://api.jquery.com/hasClass/).
    */
-  bool contains(String value);
+  bool contains(Object value);
 
   /**
    * Add the class [value] to element.
@@ -93,7 +93,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void removeAll(Iterable<String> iterable);
+  void removeAll(Iterable<Object> iterable);
 
   /**
    * Toggles all classes specified in [iterable] on element.
@@ -151,11 +151,11 @@
 
   String join([String separator = ""]) => readClasses().join(separator);
 
-  Iterable map(f(String element)) => readClasses().map(f);
+  Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(String e)) => readClasses().map(f);
 
   Iterable<String> where(bool f(String element)) => readClasses().where(f);
 
-  Iterable expand(Iterable f(String element)) => readClasses().expand(f);
+  Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(String element)) => readClasses().expand(f);
 
   bool every(bool f(String element)) => readClasses().every(f);
 
@@ -171,8 +171,8 @@
     return readClasses().reduce(combine);
   }
 
-  dynamic fold(dynamic initialValue,
-      dynamic combine(dynamic previousValue, String element)) {
+  dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+      dynamic/*=T*/ combine(var/*=T*/ previousValue, String element)) {
     return readClasses().fold(initialValue, combine);
   }
   // interface Collection - END
@@ -184,10 +184,10 @@
    * This is the Dart equivalent of jQuery's
    * [hasClass](http://api.jquery.com/hasClass/).
    */
-  bool contains(String value) => readClasses().contains(value);
+  bool contains(Object value) => readClasses().contains(value);
 
   /** Lookup from the Set interface. Not interesting for a String set. */
-  String lookup(String value) => contains(value) ? value : null;
+  String lookup(Object value) => contains(value) ? value as String : null;
 
   /**
    * Add the class [value] to element.
@@ -233,7 +233,7 @@
    * This is the Dart equivalent of jQuery's
    * [removeClass](http://api.jquery.com/removeClass/).
    */
-  void removeAll(Iterable<String> iterable) {
+  void removeAll(Iterable<Object> iterable) {
     modify((s) => s.removeAll(iterable));
   }
 
@@ -251,7 +251,7 @@
     iterable.forEach((e) => toggle(e, shouldAdd));
   }
 
-  void retainAll(Iterable<String> iterable) {
+  void retainAll(Iterable<Object> iterable) {
     modify((s) => s.retainAll(iterable));
   }
 
@@ -263,10 +263,10 @@
     modify((s) => s.retainWhere(test));
   }
 
-  bool containsAll(Iterable<String> collection) =>
+  bool containsAll(Iterable<Object> collection) =>
       readClasses().containsAll(collection);
 
-  Set<String> intersection(Set<String> other) =>
+  Set<String> intersection(Set<Object> other) =>
       readClasses().intersection(other);
 
   Set<String> union(Set<String> other) => readClasses().union(other);
@@ -285,9 +285,9 @@
   Iterable<String> skip(int n) => readClasses().skip(n);
   Iterable<String> skipWhile(bool test(String value)) =>
       readClasses().skipWhile(test);
-  dynamic firstWhere(bool test(String value), {Object orElse()}) =>
+  String firstWhere(bool test(String value), {String orElse()}) =>
       readClasses().firstWhere(test, orElse: orElse);
-  dynamic lastWhere(bool test(String value), {Object orElse()}) =>
+  String lastWhere(bool test(String value), {String orElse()}) =>
       readClasses().lastWhere(test, orElse: orElse);
   String singleWhere(bool test(String value)) =>
       readClasses().singleWhere(test);
diff --git a/lib/src/encoding_parser.dart b/lib/src/encoding_parser.dart
index fd64ff9..0b84989 100644
--- a/lib/src/encoding_parser.dart
+++ b/lib/src/encoding_parser.dart
@@ -121,6 +121,14 @@
   }
 }
 
+typedef bool _MethodHandler();
+
+class _DispatchEntry {
+  final String pattern;
+  final _MethodHandler handler;
+  _DispatchEntry(this.pattern, this.handler);
+}
+
 /// Mini parser for detecting character encoding from meta elements.
 class EncodingParser {
   final EncodingBytes data;
@@ -133,19 +141,19 @@
 
   String getEncoding() {
     final methodDispatch = [
-      ["<!--", handleComment],
-      ["<meta", handleMeta],
-      ["</", handlePossibleEndTag],
-      ["<!", handleOther],
-      ["<?", handleOther],
-      ["<", handlePossibleStartTag]
+        new _DispatchEntry("<!--", handleComment),
+        new _DispatchEntry("<meta", handleMeta),
+        new _DispatchEntry("</", handlePossibleEndTag),
+        new _DispatchEntry("<!", handleOther),
+        new _DispatchEntry("<?", handleOther),
+        new _DispatchEntry("<", handlePossibleStartTag),
     ];
 
     try {
       for (;;) {
         for (var dispatch in methodDispatch) {
-          if (data.matchBytes(dispatch[0])) {
-            var keepParsing = dispatch[1]();
+          if (data.matchBytes(dispatch.pattern)) {
+            var keepParsing = dispatch.handler();
             if (keepParsing) break;
 
             // We found an encoding. Stop.
@@ -154,7 +162,7 @@
         }
         data.position += 1;
       }
-    } on StateError catch (e) {
+    } on StateError catch (_) {
       // Catch this here to match behavior of Python's StopIteration
       // TODO(jmesserly): refactor to not use exceptions
     }
@@ -352,12 +360,12 @@
         try {
           data.skipUntil(isWhitespace);
           return data.slice(oldPosition, data.position);
-        } on StateError catch (e) {
+        } on StateError catch (_) {
           //Return the whole remaining value
           return data.slice(oldPosition);
         }
       }
-    } on StateError catch (e) {
+    } on StateError catch (_) {
       return null;
     }
   }
diff --git a/lib/src/list_proxy.dart b/lib/src/list_proxy.dart
index 99acdb6..5df1ed4 100644
--- a/lib/src/list_proxy.dart
+++ b/lib/src/list_proxy.dart
@@ -20,11 +20,14 @@
 
   // TODO(jmesserly): This should be on List.
   // See http://code.google.com/p/dart/issues/detail?id=947
-  bool remove(E item) {
-    int i = indexOf(item);
-    if (i == -1) return false;
-    removeAt(i);
-    return true;
+  bool remove(Object item) {
+    if (item is E) {
+      int i = indexOf(item);
+      if (i == -1) return false;
+      removeAt(i);
+      return true;
+    }
+    return false;
   }
 
   void insert(int index, E item) => _list.insert(index, item);
@@ -81,7 +84,7 @@
 
   List<E> getRange(int start, int end) => _list.getRange(start, end);
 
-  void setRange(int start, int length, List<E> from, [int startFrom = 0]) {
+  void setRange(int start, int length, Iterable<E> from, [int startFrom = 0]) {
     _list.setRange(start, length, from, startFrom);
   }
   void removeRange(int start, int length) {
diff --git a/lib/src/query_selector.dart b/lib/src/query_selector.dart
index e586d1a..3aa45f2 100644
--- a/lib/src/query_selector.dart
+++ b/lib/src/query_selector.dart
@@ -3,6 +3,7 @@
 
 import 'package:csslib/parser.dart' as css;
 import 'package:csslib/parser.dart' show TokenKind;
+import 'package:csslib/src/messages.dart' show Message;
 import 'package:csslib/visitor.dart'; // the CSSOM
 import 'package:html/dom.dart';
 import 'package:html/src/constants.dart' show isWhitespaceCC;
@@ -14,7 +15,7 @@
     new SelectorEvaluator().querySelector(node, _parseSelectorList(selector));
 
 List<Element> querySelectorAll(Node node, String selector) {
-  var results = [];
+  var results = <Element>[];
   new SelectorEvaluator().querySelectorAll(
       node, _parseSelectorList(selector), results);
   return results;
@@ -22,7 +23,7 @@
 
 // http://dev.w3.org/csswg/selectors-4/#grouping
 SelectorGroup _parseSelectorList(String selector) {
-  var errors = [];
+  var errors = <Message>[];
   var group = css.parseSelectorGroup(selector, errors: errors);
   if (group == null || errors.isNotEmpty) {
     throw new FormatException("'$selector' is not a valid selector: $errors");
diff --git a/lib/src/tokenizer.dart b/lib/src/tokenizer.dart
index 3273858..68cb6dc 100644
--- a/lib/src/tokenizer.dart
+++ b/lib/src/tokenizer.dart
@@ -12,7 +12,7 @@
 // TODO(jmesserly): we could use a better data structure here like a trie, if
 // we had it implemented in Dart.
 Map<String, List<String>> entitiesByFirstChar = (() {
-  var result = {};
+  var result = <String, List<String>>{};
   for (var k in entities.keys) {
     result.putIfAbsent(k[0], () => []).add(k);
   }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index fb58cf1..16837b0 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -43,7 +43,7 @@
 }
 
 // Like the python [:] operator.
-List slice(List list, int start, [int end]) {
+List/*<T>*/ slice/*<T>*/(List/*<T>*/ list, int start, [int end]) {
   if (end == null) end = list.length;
   if (end < 0) end += list.length;
 
diff --git a/pubspec.yaml b/pubspec.yaml
index 697d1c8..4a595c1 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,12 +1,12 @@
 name: html
-version: 0.12.2+2
+version: 0.13.0
 author: Dart Team <misc@dartlang.org>
 description: A library for working with HTML documents. Previously known as html5lib.
 homepage: https://github.com/dart-lang/html
 environment:
   sdk: '>=1.2.0 <2.0.0'
 dependencies:
-  csslib: '>=0.10.0 <0.14.0'
+  csslib: '>=0.13.2 <0.14.0'
   source_span: '>=1.0.0 <2.0.0'
   utf: '>=0.9.0 <0.10.0'
 dev_dependencies:
diff --git a/test/dom_test.dart b/test/dom_test.dart
index d4e0809..404a488 100644
--- a/test/dom_test.dart
+++ b/test/dom_test.dart
@@ -26,8 +26,8 @@
     test('getElementById', () {
       var foo = doc.body.nodes[0];
       var Foo = foo.nodes[2];
-      expect(foo.id, 'foo');
-      expect(Foo.id, 'Foo');
+      expect((foo as Element).id, 'foo');
+      expect((Foo as Element).id, 'Foo');
       expect(doc.getElementById('foo'), foo);
       expect(doc.getElementById('Foo'), Foo);
     });
@@ -36,8 +36,8 @@
       var foo = doc.body.nodes[0];
       var barBaz = foo.nodes[0];
       var quxBaz = foo.nodes[1];
-      expect(barBaz.className, ' bar baz');
-      expect(quxBaz.className, 'qux  baz ');
+      expect((barBaz as Element).className, ' bar baz');
+      expect((quxBaz as Element).className, 'qux  baz ');
       expect(doc.getElementsByClassName('baz'), [barBaz, quxBaz]);
       expect(doc.getElementsByClassName('bar '), [barBaz]);
       expect(doc.getElementsByClassName('  qux'), [quxBaz]);
@@ -57,83 +57,83 @@
     test('add', () {
       var doc = parse('<body>');
       doc.body.nodes.add(parseFragment('<x-foo>'));
-      expect(doc.body.nodes[0].localName, 'x-foo');
+      expect((doc.body.nodes[0] as Element).localName, 'x-foo');
       doc.body.nodes.add(parseFragment('<x-bar>'));
-      expect(doc.body.nodes[1].localName, 'x-bar');
+      expect((doc.body.nodes[1] as Element).localName, 'x-bar');
     });
 
     test('addLast', () {
       var doc = parse('<body>');
       doc.body.nodes.addLast(parseFragment('<x-foo>'));
-      expect(doc.body.nodes[0].localName, 'x-foo');
+      expect((doc.body.nodes[0] as Element).localName, 'x-foo');
       doc.body.nodes.addLast(parseFragment('<x-bar>'));
-      expect(doc.body.nodes[1].localName, 'x-bar');
+      expect((doc.body.nodes[1] as Element).localName, 'x-bar');
     });
 
     test('addAll', () {
       var doc = parse('<body><x-a></x-a>');
       doc.body.nodes.addAll([parseFragment('<x-b></x-b><x-c></x-c>')]);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'x-b');
-      expect(doc.body.nodes[2].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'x-b');
+      expect((doc.body.nodes[2] as Element).localName, 'x-c');
     });
 
     test('insert', () {
       var doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insert(0, parseFragment('<x-b></x-b><x-c></x-c>'));
-      expect(doc.body.nodes[0].localName, 'x-b');
-      expect(doc.body.nodes[1].localName, 'x-c');
-      expect(doc.body.nodes[2].localName, 'x-a');
+      expect((doc.body.nodes[0] as Element).localName, 'x-b');
+      expect((doc.body.nodes[1] as Element).localName, 'x-c');
+      expect((doc.body.nodes[2] as Element).localName, 'x-a');
 
       doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insert(1, parseFragment('<x-b></x-b><x-c></x-c>'));
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'x-b');
-      expect(doc.body.nodes[2].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'x-b');
+      expect((doc.body.nodes[2] as Element).localName, 'x-c');
 
       doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insert(0, parseFragment('<x-b></x-b>'));
       doc.body.nodes.insert(1, parseFragment('<x-c></x-c>'));
-      expect(doc.body.nodes[0].localName, 'x-b');
-      expect(doc.body.nodes[1].localName, 'x-c');
-      expect(doc.body.nodes[2].localName, 'x-a');
+      expect((doc.body.nodes[0] as Element).localName, 'x-b');
+      expect((doc.body.nodes[1] as Element).localName, 'x-c');
+      expect((doc.body.nodes[2] as Element).localName, 'x-a');
     });
 
     test('insertAll', () {
       var doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insertAll(0, [parseFragment('<x-b></x-b><x-c></x-c>')]);
-      expect(doc.body.nodes[0].localName, 'x-b');
-      expect(doc.body.nodes[1].localName, 'x-c');
-      expect(doc.body.nodes[2].localName, 'x-a');
+      expect((doc.body.nodes[0] as Element).localName, 'x-b');
+      expect((doc.body.nodes[1] as Element).localName, 'x-c');
+      expect((doc.body.nodes[2] as Element).localName, 'x-a');
       expect(doc.body.nodes.length, 3);
 
       doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insertAll(1, [parseFragment('<x-b></x-b><x-c></x-c>')]);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'x-b');
-      expect(doc.body.nodes[2].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'x-b');
+      expect((doc.body.nodes[2] as Element).localName, 'x-c');
 
       doc = parse('<body><x-a></x-a>');
       doc.body.nodes.insertAll(0, [parseFragment('<x-b></x-b>')]);
       doc.body.nodes.insertAll(1, [parseFragment('<x-c></x-c>')]);
-      expect(doc.body.nodes[0].localName, 'x-b');
-      expect(doc.body.nodes[1].localName, 'x-c');
-      expect(doc.body.nodes[2].localName, 'x-a');
+      expect((doc.body.nodes[0] as Element).localName, 'x-b');
+      expect((doc.body.nodes[1] as Element).localName, 'x-c');
+      expect((doc.body.nodes[2] as Element).localName, 'x-a');
     });
 
     test('operator []=', () {
       var doc = parse('<body><x-a></x-a>');
       doc.body.nodes[0] = parseFragment('<x-b></x-b><x-c></x-c>');
-      expect(doc.body.nodes[0].localName, 'x-b');
-      expect(doc.body.nodes[1].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-b');
+      expect((doc.body.nodes[1] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 2);
 
       doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes[1] = parseFragment('<y-b></y-b><y-c></y-c>');
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
-      expect(doc.body.nodes[3].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
+      expect((doc.body.nodes[3] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 4);
     });
 
@@ -141,18 +141,18 @@
       var fragment = parseFragment('<y-b></y-b><y-c></y-c>');
       var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes.setRange(1, 2, fragment.nodes, 0);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
       expect(doc.body.nodes.length, 3);
 
       fragment = parseFragment('<y-b></y-b><y-c></y-c>');
       doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes.setRange(1, 1, [fragment], 0);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
-      expect(doc.body.nodes[3].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
+      expect((doc.body.nodes[3] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 4);
     });
 
@@ -160,19 +160,19 @@
       var fragment = parseFragment('<y-b></y-b><y-c></y-c>');
       var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes.replaceRange(1, 2, fragment.nodes);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
-      expect(doc.body.nodes[3].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
+      expect((doc.body.nodes[3] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 4);
 
       fragment = parseFragment('<y-b></y-b><y-c></y-c>');
       doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes.replaceRange(1, 2, [fragment]);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
-      expect(doc.body.nodes[3].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
+      expect((doc.body.nodes[3] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 4);
     });
 
@@ -180,10 +180,10 @@
       var fragment = parseFragment('<y-b></y-b><y-c></y-c>');
       var doc = parse('<body><x-a></x-a><x-b></x-b><x-c></x-c>');
       doc.body.nodes[1].replaceWith(fragment);
-      expect(doc.body.nodes[0].localName, 'x-a');
-      expect(doc.body.nodes[1].localName, 'y-b');
-      expect(doc.body.nodes[2].localName, 'y-c');
-      expect(doc.body.nodes[3].localName, 'x-c');
+      expect((doc.body.nodes[0] as Element).localName, 'x-a');
+      expect((doc.body.nodes[1] as Element).localName, 'y-b');
+      expect((doc.body.nodes[2] as Element).localName, 'y-c');
+      expect((doc.body.nodes[3] as Element).localName, 'x-c');
       expect(doc.body.nodes.length, 4);
     });
   });
diff --git a/test/parser_feature_test.dart b/test/parser_feature_test.dart
index 54d68a9..6d3af0c 100644
--- a/test/parser_feature_test.dart
+++ b/test/parser_feature_test.dart
@@ -25,12 +25,12 @@
 
   test('namespace html elements on', () {
     var doc = new HtmlParser('', tree: new TreeBuilder(true)).parse();
-    expect(doc.nodes[0].namespaceUri, Namespaces.html);
+    expect((doc.nodes[0] as Element).namespaceUri, Namespaces.html);
   });
 
   test('namespace html elements off', () {
     var doc = new HtmlParser('', tree: new TreeBuilder(false)).parse();
-    expect(doc.nodes[0].namespaceUri, null);
+    expect((doc.nodes[0] as Element).namespaceUri, null);
   });
 
   test('parse error spans - full', () {
@@ -290,7 +290,7 @@
     expect(e.text, 'bar');
 
     c.text = 'qux';
-    expect(c.data, 'qux');
+    expect((c as Comment).data, 'qux');
     expect(c.text, 'qux');
     expect(e.text, 'bar');
   });
@@ -310,7 +310,7 @@
   });
 
   group('Encoding pre-parser', () {
-    getEncoding(s) => new EncodingParser(s.codeUnits).getEncoding();
+    getEncoding(String s) => new EncodingParser(s.codeUnits).getEncoding();
 
     test('gets encoding from meta charset', () {
       expect(getEncoding('<meta charset="utf-16">'), 'utf-16');
@@ -473,4 +473,4 @@
       }
     });
   });
-}
\ No newline at end of file
+}
diff --git a/test/run_all.dart b/test/run_all.dart
index 14e6b34..d2bf9ce 100644
--- a/test/run_all.dart
+++ b/test/run_all.dart
@@ -17,7 +17,7 @@
   var pattern = new RegExp(args.length > 0 ? args[0] : '.');
   useCompactVMConfiguration();
 
-  void addGroup(testFile, testMain) {
+  void addGroup(testFile, void testMain()) {
     if (pattern.hasMatch(testFile)) {
       group(testFile.replaceAll('_test.dart', ':'), testMain);
     }
diff --git a/test/support.dart b/test/support.dart
index 1b4c0b4..1bb2550 100644
--- a/test/support.dart
+++ b/test/support.dart
@@ -10,7 +10,7 @@
 
 typedef TreeBuilder TreeBuilderFactory(bool namespaceHTMLElements);
 
-Map _treeTypes;
+Map<String, TreeBuilderFactory> _treeTypes;
 Map<String, TreeBuilderFactory> get treeTypes {
   if (_treeTypes == null) {
     // TODO(jmesserly): add DOM here once it's implemented
@@ -133,13 +133,16 @@
     indent -= 2;
   }
 
-  visitDocument(node) {
+  visitDocument(node) => _visitDocumentOrFragment(node);
+
+  _visitDocumentOrFragment(node) {
     indent += 1;
     for (var child in node.nodes) visit(child);
     indent -= 1;
   }
 
-  visitDocumentFragment(DocumentFragment node) => visitDocument(node);
+  visitDocumentFragment(DocumentFragment node) =>
+      _visitDocumentOrFragment(node);
 
   visitElement(Element node) {
     _newline();