Clean up lerp() methods and their documentation. (#13684)

This cleans up lerp, lerpFrom, lerpTo, and scale methods, and their
documentation.

Fixes https://github.com/flutter/flutter/issues/12377.
diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart
index d651a80..2233493 100644
--- a/packages/flutter/lib/src/cupertino/route.dart
+++ b/packages/flutter/lib/src/cupertino/route.dart
@@ -589,23 +589,39 @@
 class _CupertinoEdgeShadowDecoration extends Decoration {
   const _CupertinoEdgeShadowDecoration({ this.edgeGradient });
 
-  /// A Decoration with no decorating properties.
+  // An edge shadow decoration where the shadow is null. This is used
+  // for interpolating from no shadow.
   static const _CupertinoEdgeShadowDecoration none =
       const _CupertinoEdgeShadowDecoration();
 
-  /// A gradient to draw to the left of the box being decorated.
-  /// Alignments are relative to the original box translated one box
-  /// width to the left.
+  // A gradient to draw to the left of the box being decorated.
+  // Alignments are relative to the original box translated one box
+  // width to the left.
   final LinearGradient edgeGradient;
 
-  /// Linearly interpolate between two edge shadow decorations decorations.
-  ///
-  /// See also [Decoration.lerp].
+  // Linearly interpolate between two edge shadow decorations decorations.
+  //
+  // The `t` argument represents position on the timeline, with 0.0 meaning
+  // that the interpolation has not started, returning `a` (or something
+  // equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  // returning `b` (or something equivalent to `b`), and values in between
+  // meaning that the interpolation is at the relevant point on the timeline
+  // between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  // 1.0, so negative values and values greater than 1.0 are valid (and can
+  // easily be generated by curves such as [Curves.elasticInOut]).
+  //
+  // Values for `t` are usually obtained from an [Animation<double>], such as
+  // an [AnimationController].
+  //
+  // See also:
+  //
+  //  * [Decoration.lerp].
   static _CupertinoEdgeShadowDecoration lerp(
     _CupertinoEdgeShadowDecoration a,
     _CupertinoEdgeShadowDecoration b,
-    double t
+    double t,
   ) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     return new _CupertinoEdgeShadowDecoration(
diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart
index bbc9056..3821623 100644
--- a/packages/flutter/lib/src/material/theme_data.dart
+++ b/packages/flutter/lib/src/material/theme_data.dart
@@ -519,40 +519,53 @@
   /// Linearly interpolate between two themes.
   ///
   /// The arguments must not be null.
-  static ThemeData lerp(ThemeData begin, ThemeData end, double t) {
-    assert(begin != null);
-    assert(end != null);
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static ThemeData lerp(ThemeData a, ThemeData b, double t) {
+    assert(a != null);
+    assert(b != null);
+    assert(t != null);
     return new ThemeData.raw(
-      brightness: t < 0.5 ? begin.brightness : end.brightness,
-      primaryColor: Color.lerp(begin.primaryColor, end.primaryColor, t),
-      primaryColorBrightness: t < 0.5 ? begin.primaryColorBrightness : end.primaryColorBrightness,
-      canvasColor: Color.lerp(begin.canvasColor, end.canvasColor, t),
-      scaffoldBackgroundColor: Color.lerp(begin.scaffoldBackgroundColor, end.scaffoldBackgroundColor, t),
-      cardColor: Color.lerp(begin.cardColor, end.cardColor, t),
-      dividerColor: Color.lerp(begin.dividerColor, end.dividerColor, t),
-      highlightColor: Color.lerp(begin.highlightColor, end.highlightColor, t),
-      splashColor: Color.lerp(begin.splashColor, end.splashColor, t),
-      selectedRowColor: Color.lerp(begin.selectedRowColor, end.selectedRowColor, t),
-      unselectedWidgetColor: Color.lerp(begin.unselectedWidgetColor, end.unselectedWidgetColor, t),
-      disabledColor: Color.lerp(begin.disabledColor, end.disabledColor, t),
-      buttonColor: Color.lerp(begin.buttonColor, end.buttonColor, t),
-      secondaryHeaderColor: Color.lerp(begin.secondaryHeaderColor, end.secondaryHeaderColor, t),
-      textSelectionColor: Color.lerp(begin.textSelectionColor, end.textSelectionColor, t),
-      textSelectionHandleColor: Color.lerp(begin.textSelectionHandleColor, end.textSelectionHandleColor, t),
-      backgroundColor: Color.lerp(begin.backgroundColor, end.backgroundColor, t),
-      dialogBackgroundColor: Color.lerp(begin.dialogBackgroundColor, end.dialogBackgroundColor, t),
-      accentColor: Color.lerp(begin.accentColor, end.accentColor, t),
-      accentColorBrightness: t < 0.5 ? begin.accentColorBrightness : end.accentColorBrightness,
-      indicatorColor: Color.lerp(begin.indicatorColor, end.indicatorColor, t),
-      hintColor: Color.lerp(begin.hintColor, end.hintColor, t),
-      errorColor: Color.lerp(begin.errorColor, end.errorColor, t),
-      textTheme: TextTheme.lerp(begin.textTheme, end.textTheme, t),
-      primaryTextTheme: TextTheme.lerp(begin.primaryTextTheme, end.primaryTextTheme, t),
-      accentTextTheme: TextTheme.lerp(begin.accentTextTheme, end.accentTextTheme, t),
-      iconTheme: IconThemeData.lerp(begin.iconTheme, end.iconTheme, t),
-      primaryIconTheme: IconThemeData.lerp(begin.primaryIconTheme, end.primaryIconTheme, t),
-      accentIconTheme: IconThemeData.lerp(begin.accentIconTheme, end.accentIconTheme, t),
-      platform: t < 0.5 ? begin.platform : end.platform
+      brightness: t < 0.5 ? a.brightness : b.brightness,
+      primaryColor: Color.lerp(a.primaryColor, b.primaryColor, t),
+      primaryColorBrightness: t < 0.5 ? a.primaryColorBrightness : b.primaryColorBrightness,
+      canvasColor: Color.lerp(a.canvasColor, b.canvasColor, t),
+      scaffoldBackgroundColor: Color.lerp(a.scaffoldBackgroundColor, b.scaffoldBackgroundColor, t),
+      cardColor: Color.lerp(a.cardColor, b.cardColor, t),
+      dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t),
+      highlightColor: Color.lerp(a.highlightColor, b.highlightColor, t),
+      splashColor: Color.lerp(a.splashColor, b.splashColor, t),
+      selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t),
+      unselectedWidgetColor: Color.lerp(a.unselectedWidgetColor, b.unselectedWidgetColor, t),
+      disabledColor: Color.lerp(a.disabledColor, b.disabledColor, t),
+      buttonColor: Color.lerp(a.buttonColor, b.buttonColor, t),
+      secondaryHeaderColor: Color.lerp(a.secondaryHeaderColor, b.secondaryHeaderColor, t),
+      textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t),
+      textSelectionHandleColor: Color.lerp(a.textSelectionHandleColor, b.textSelectionHandleColor, t),
+      backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
+      dialogBackgroundColor: Color.lerp(a.dialogBackgroundColor, b.dialogBackgroundColor, t),
+      accentColor: Color.lerp(a.accentColor, b.accentColor, t),
+      accentColorBrightness: t < 0.5 ? a.accentColorBrightness : b.accentColorBrightness,
+      indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t),
+      hintColor: Color.lerp(a.hintColor, b.hintColor, t),
+      errorColor: Color.lerp(a.errorColor, b.errorColor, t),
+      textTheme: TextTheme.lerp(a.textTheme, b.textTheme, t),
+      primaryTextTheme: TextTheme.lerp(a.primaryTextTheme, b.primaryTextTheme, t),
+      accentTextTheme: TextTheme.lerp(a.accentTextTheme, b.accentTextTheme, t),
+      iconTheme: IconThemeData.lerp(a.iconTheme, b.iconTheme, t),
+      primaryIconTheme: IconThemeData.lerp(a.primaryIconTheme, b.primaryIconTheme, t),
+      accentIconTheme: IconThemeData.lerp(a.accentIconTheme, b.accentIconTheme, t),
+      platform: t < 0.5 ? a.platform : b.platform,
     );
   }
 
diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart
index 0acc9b4..2e131af 100644
--- a/packages/flutter/lib/src/material/typography.dart
+++ b/packages/flutter/lib/src/material/typography.dart
@@ -284,19 +284,36 @@
   }
 
   /// Linearly interpolate between two text themes.
-  static TextTheme lerp(TextTheme begin, TextTheme end, double t) {
+  ///
+  /// The arguments must not be null.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static TextTheme lerp(TextTheme a, TextTheme b, double t) {
+    assert(a != null);
+    assert(b != null);
+    assert(t != null);
     return new TextTheme(
-      display4: TextStyle.lerp(begin.display4, end.display4, t),
-      display3: TextStyle.lerp(begin.display3, end.display3, t),
-      display2: TextStyle.lerp(begin.display2, end.display2, t),
-      display1: TextStyle.lerp(begin.display1, end.display1, t),
-      headline: TextStyle.lerp(begin.headline, end.headline, t),
-      title: TextStyle.lerp(begin.title, end.title, t),
-      subhead: TextStyle.lerp(begin.subhead, end.subhead, t),
-      body2: TextStyle.lerp(begin.body2, end.body2, t),
-      body1: TextStyle.lerp(begin.body1, end.body1, t),
-      caption: TextStyle.lerp(begin.caption, end.caption, t),
-      button: TextStyle.lerp(begin.button, end.button, t),
+      display4: TextStyle.lerp(a.display4, b.display4, t),
+      display3: TextStyle.lerp(a.display3, b.display3, t),
+      display2: TextStyle.lerp(a.display2, b.display2, t),
+      display1: TextStyle.lerp(a.display1, b.display1, t),
+      headline: TextStyle.lerp(a.headline, b.headline, t),
+      title: TextStyle.lerp(a.title, b.title, t),
+      subhead: TextStyle.lerp(a.subhead, b.subhead, t),
+      body2: TextStyle.lerp(a.body2, b.body2, t),
+      body1: TextStyle.lerp(a.body1, b.body1, t),
+      caption: TextStyle.lerp(a.caption, b.caption, t),
+      button: TextStyle.lerp(a.button, b.button, t),
     );
   }
 
diff --git a/packages/flutter/lib/src/painting/alignment.dart b/packages/flutter/lib/src/painting/alignment.dart
index d21fa5d..d153182 100644
--- a/packages/flutter/lib/src/painting/alignment.dart
+++ b/packages/flutter/lib/src/painting/alignment.dart
@@ -84,7 +84,20 @@
   /// this is not reflected in the type system). Otherwise, an object
   /// representing a combination of both is returned. That object can be turned
   /// into a concrete [Alignment] using [resolve].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static AlignmentGeometry lerp(AlignmentGeometry a, AlignmentGeometry b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -320,7 +333,20 @@
   /// Linearly interpolate between two [Alignment]s.
   ///
   /// If either is null, this function interpolates from [Alignment.center].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static Alignment lerp(Alignment a, Alignment b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -498,7 +524,20 @@
   /// Linearly interpolate between two [AlignmentDirectional]s.
   ///
   /// If either is null, this function interpolates from [AlignmentDirectional.center].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static AlignmentDirectional lerp(AlignmentDirectional a, AlignmentDirectional b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/border_radius.dart b/packages/flutter/lib/src/painting/border_radius.dart
index 6439a5a..3656108 100644
--- a/packages/flutter/lib/src/painting/border_radius.dart
+++ b/packages/flutter/lib/src/painting/border_radius.dart
@@ -126,7 +126,20 @@
   /// this is not reflected in the type system). Otherwise, an object
   /// representing a combination of both is returned. That object can be turned
   /// into a concrete [BorderRadius] using [resolve].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BorderRadiusGeometry lerp(BorderRadiusGeometry a, BorderRadiusGeometry b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     a ??= BorderRadius.zero;
@@ -467,7 +480,20 @@
   /// Linearly interpolate between two [BorderRadius] objects.
   ///
   /// If either is null, this function interpolates from [BorderRadius.zero].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BorderRadius lerp(BorderRadius a, BorderRadius b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -681,7 +707,20 @@
   /// Linearly interpolate between two [BorderRadiusDirectional] objects.
   ///
   /// If either is null, this function interpolates from [BorderRadiusDirectional.zero].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BorderRadiusDirectional lerp(BorderRadiusDirectional a, BorderRadiusDirectional b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/borders.dart b/packages/flutter/lib/src/painting/borders.dart
index d1741b1..0bc4338 100644
--- a/packages/flutter/lib/src/painting/borders.dart
+++ b/packages/flutter/lib/src/painting/borders.dart
@@ -130,11 +130,22 @@
     );
   }
 
-  /// Creates a copy of this border but with the width scaled by the given factor.
+  /// Creates a copy of this border side description but with the width scaled
+  /// by the factor `t`.
   ///
-  /// Since a zero width is painted as a hairline width rather than no border at
-  /// all, the zero factor is special-cased to instead change the style no
-  /// [BorderStyle.none].
+  /// The `t` argument represents the multiplicand, or the position on the
+  /// timeline for an interpolation from nothing to `this`, with 0.0 meaning
+  /// that the the object returned should be the nil variant of this object, 1.0
+  /// meaning that no change should be applied, returning `this` (or something
+  /// equivalent to `this`), and other values meaning that the object should be
+  /// multiplied by `t`. Negative values are treated like zero.
+  ///
+  /// Since a zero width is normally painted as a hairline width rather than no
+  /// border at all, the zero factor is special-cased to instead change the
+  /// style no [BorderStyle.none].
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   BorderSide scale(double t) {
     assert(t != null);
     return new BorderSide(
@@ -186,6 +197,18 @@
   /// Linearly interpolate between two border sides.
   ///
   /// The arguments must not be null.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BorderSide lerp(BorderSide a, BorderSide b, double t) {
     assert(a != null);
     assert(b != null);
@@ -272,7 +295,7 @@
   /// computing their [dimensions].
   EdgeInsetsGeometry get dimensions;
 
-  /// Attempts to create a new object that represents the amalgamation of [this]
+  /// Attempts to create a new object that represents the amalgamation of `this`
   /// border and the `other` border.
   ///
   /// If the type of the other border isn't known, or the given instance cannot
@@ -297,10 +320,32 @@
     return add(other) ?? other.add(this, reversed: true) ?? new _CompoundBorder(<ShapeBorder>[other, this]);
   }
 
-  /// Creates a new border with the widths of this border multiplied by `t`.
+  /// Creates a copy of this border, scaled by the factor `t`.
+  ///
+  /// Typically this means scaling the width of the border's side, but it can
+  /// also include scaling other artifacts of the border, e.g. the border radius
+  /// of a [RoundedRectangleBorder].
+  ///
+  /// The `t` argument represents the multiplicand, or the position on the
+  /// timeline for an interpolation from nothing to `this`, with 0.0 meaning
+  /// that the the object returned should be the nil variant of this object, 1.0
+  /// meaning that no change should be applied, returning `this` (or something
+  /// equivalent to `this`), and other values meaning that the object should be
+  /// multiplied by `t`. Negative values are allowed but may be meaningless
+  /// (they correspond to extrapolating the interpolation from this object to
+  /// nothing, and going beyond nothing)
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
+  /// See also:
+  ///
+  ///  * [BorderSide.scale], which most [ShapeBorder] subclasses defer to for
+  ///    the actual computation.
   ShapeBorder scale(double t);
 
-  /// Linearly interpolates from `a` to [this].
+  /// Linearly interpolates from another [ShapeBorder] (possibly of another
+  /// class) to `this`.
   ///
   /// When implementing this method in subclasses, return null if this class
   /// cannot interpolate from `a`. In that case, [lerp] will try `a`'s [lerpTo]
@@ -309,6 +354,19 @@
   /// The base class implementation handles the case of `a` being null by
   /// deferring to [scale].
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `this` (or something equivalent to `this`), and values in
+  /// between meaning that the interpolation is at the relevant point on the
+  /// timeline between `a` and `this`. The interpolation can be extrapolated
+  /// beyond 0.0 and 1.0, so negative values and values greater than 1.0 are
+  /// valid (and can easily be generated by curves such as
+  /// [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [ShapeBorder.lerp].
   @protected
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
@@ -317,7 +375,8 @@
     return null;
   }
 
-  /// Linearly interpolates from [this] to `b`.
+  /// Linearly interpolates from `this` to another [ShapeBorder] (possibly of
+  /// another class).
   ///
   /// This is called if `b`'s [lerpTo] did not know how to handle this class.
   ///
@@ -328,6 +387,18 @@
   /// The base class implementation handles the case of `b` being null by
   /// deferring to [scale].
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `this` (or something
+  /// equivalent to `this`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `this` and `b`. The interpolation can be extrapolated beyond 0.0
+  /// and 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [ShapeBorder.lerp].
   @protected
   ShapeBorder lerpTo(ShapeBorder b, double t) {
@@ -336,19 +407,32 @@
     return null;
   }
 
-  /// Linearly interpolates from `begin` to `end`.
+  /// Linearly interpolates between two [ShapeBorder]s.
   ///
-  /// This defers to `end`'s [lerpTo] function if `end` is not null. If `end` is
-  /// null or if its [lerpTo] returns null, it uses `begin`'s [lerpFrom]
-  /// function instead. If both return null, it returns `begin` before `t=0.5`
-  /// and `end` after `t=0.5`.
-  static ShapeBorder lerp(ShapeBorder begin, ShapeBorder end, double t) {
+  /// This defers to `b`'s [lerpTo] function if `b` is not null. If `b` is
+  /// null or if its [lerpTo] returns null, it uses `a`'s [lerpFrom]
+  /// function instead. If both return null, it returns `a` before `t=0.5`
+  /// and `b` after `t=0.5`.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static ShapeBorder lerp(ShapeBorder a, ShapeBorder b, double t) {
+    assert(t != null);
     ShapeBorder result;
-    if (end != null)
-      result = end.lerpFrom(begin, t);
-    if (result == null && begin != null)
-      result = begin.lerpTo(end, t);
-    return result ?? (t < 0.5 ? begin : end);
+    if (b != null)
+      result = b.lerpFrom(a, t);
+    if (result == null && a != null)
+      result = a.lerpTo(b, t);
+    return result ?? (t < 0.5 ? a : b);
   }
 
   /// Create a [Path] that describes the outer edge of the border.
@@ -480,6 +564,7 @@
   }
 
   static _CompoundBorder lerp(ShapeBorder a, ShapeBorder b, double t) {
+    assert(t != null);
     assert(a is _CompoundBorder || b is _CompoundBorder); // Not really necessary, but all call sites currently intend this.
     final List<ShapeBorder> aList = a is _CompoundBorder ? a.borders : <ShapeBorder>[a];
     final List<ShapeBorder> bList = b is _CompoundBorder ? b.borders : <ShapeBorder>[b];
diff --git a/packages/flutter/lib/src/painting/box_border.dart b/packages/flutter/lib/src/painting/box_border.dart
index 9f47030..54f4b7a 100644
--- a/packages/flutter/lib/src/painting/box_border.dart
+++ b/packages/flutter/lib/src/painting/box_border.dart
@@ -34,6 +34,8 @@
   ///
   ///  * [CircleBorder], the equivalent [ShapeBorder].
   circle,
+
+  // Don't add more, instead create a new ShapeBorder.
 }
 
 /// Base class for box borders that can paint as rectangle, circles, or rounded
@@ -95,7 +97,20 @@
   ///
   /// For a more flexible approach, consider [ShapeBorder.lerp], which would
   /// instead [add] the two sets of sides and interpolate them simultaneously.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BoxBorder lerp(BoxBorder a, BoxBorder b, double t) {
+    assert(t != null);
     if ((a is Border || a == null) && (b is Border || b == null))
       return Border.lerp(a, b, t);
     if ((a is BorderDirectional || a == null) && (b is BorderDirectional || b == null))
@@ -387,7 +402,6 @@
     return null;
   }
 
-  /// Creates a new border with the widths of this border multiplied by `t`.
   @override
   Border scale(double t) {
     return new Border(
@@ -398,13 +412,6 @@
     );
   }
 
-  /// Linearly interpolates from `a` to [this].
-  ///
-  /// If `a` is null, this defers to [scale].
-  ///
-  /// If `a` is also a [Border], this uses [Border.lerp].
-  ///
-  /// Otherwise, it defers to [ShapeBorder.lerpFrom].
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
     if (a is Border)
@@ -412,13 +419,6 @@
     return super.lerpFrom(a, t);
   }
 
-  /// Linearly interpolates from [this] to `b`.
-  ///
-  /// If `b` is null, this defers to [scale].
-  ///
-  /// If `b` is also a [Border], this uses [Border.lerp].
-  ///
-  /// Otherwise, it defers to [ShapeBorder.lerpTo].
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
     if (b is Border)
@@ -430,7 +430,20 @@
   ///
   /// If a border is null, it is treated as having four [BorderSide.none]
   /// borders.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static Border lerp(Border a, Border b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -441,7 +454,7 @@
       top: BorderSide.lerp(a.top, b.top, t),
       right: BorderSide.lerp(a.right, b.right, t),
       bottom: BorderSide.lerp(a.bottom, b.bottom, t),
-      left: BorderSide.lerp(a.left, b.left, t)
+      left: BorderSide.lerp(a.left, b.left, t),
     );
   }
 
@@ -689,7 +702,6 @@
     return null;
   }
 
-  /// Creates a new border with the widths of this border multiplied by `t`.
   @override
   BorderDirectional scale(double t) {
     return new BorderDirectional(
@@ -700,13 +712,6 @@
     );
   }
 
-  /// Linearly interpolates from `a` to [this].
-  ///
-  /// If `a` is null, this defers to [scale].
-  ///
-  /// If `a` is also a [BorderDirectional], this uses [BorderDirectional.lerp].
-  ///
-  /// Otherwise, it defers to [ShapeBorder.lerpFrom].
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
     if (a is BorderDirectional)
@@ -714,13 +719,6 @@
     return super.lerpFrom(a, t);
   }
 
-  /// Linearly interpolates from [this] to `b`.
-  ///
-  /// If `b` is null, this defers to [scale].
-  ///
-  /// If `b` is also a [BorderDirectional], this uses [BorderDirectional.lerp].
-  ///
-  /// Otherwise, it defers to [ShapeBorder.lerpTo].
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
     if (b is BorderDirectional)
@@ -732,7 +730,20 @@
   ///
   /// If a border is null, it is treated as having four [BorderSide.none]
   /// borders.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BorderDirectional lerp(BorderDirectional a, BorderDirectional b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -743,7 +754,7 @@
       top: BorderSide.lerp(a.top, b.top, t),
       end: BorderSide.lerp(a.end, b.end, t),
       bottom: BorderSide.lerp(a.bottom, b.bottom, t),
-      start: BorderSide.lerp(a.start, b.start, t)
+      start: BorderSide.lerp(a.start, b.start, t),
     );
   }
 
diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart
index 43c8a69..8a4f9d2 100644
--- a/packages/flutter/lib/src/painting/box_decoration.dart
+++ b/packages/flutter/lib/src/painting/box_decoration.dart
@@ -200,6 +200,18 @@
   /// unmodified. Otherwise, the values are computed by interpolating the
   /// properties appropriately.
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// See also:
   ///
   ///  * [Decoration.lerp], which can interpolate between any two types of
@@ -208,6 +220,7 @@
   ///    and which use [BoxDecoration.lerp] when interpolating two
   ///    [BoxDecoration]s or a [BoxDecoration] to or from null.
   static BoxDecoration lerp(BoxDecoration a, BoxDecoration b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/box_shadow.dart b/packages/flutter/lib/src/painting/box_shadow.dart
index 28b8baa..2ef2407 100644
--- a/packages/flutter/lib/src/painting/box_shadow.dart
+++ b/packages/flutter/lib/src/painting/box_shadow.dart
@@ -70,7 +70,20 @@
   /// If either box shadow is null, this function linearly interpolates from a
   /// a box shadow that matches the other box shadow in color but has a zero
   /// offset and a zero blurRadius.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -81,25 +94,38 @@
       color: Color.lerp(a.color, b.color, t),
       offset: Offset.lerp(a.offset, b.offset, t),
       blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t),
-      spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t)
+      spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t),
     );
   }
 
   /// Linearly interpolate between two lists of box shadows.
   ///
   /// If the lists differ in length, excess items are lerped with null.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static List<BoxShadow> lerpList(List<BoxShadow> a, List<BoxShadow> b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     a ??= <BoxShadow>[];
     b ??= <BoxShadow>[];
     final List<BoxShadow> result = <BoxShadow>[];
     final int commonLength = math.min(a.length, b.length);
-    for (int i = 0; i < commonLength; ++i)
+    for (int i = 0; i < commonLength; i += 1)
       result.add(BoxShadow.lerp(a[i], b[i], t));
-    for (int i = commonLength; i < a.length; ++i)
+    for (int i = commonLength; i < a.length; i += 1)
       result.add(a[i].scale(1.0 - t));
-    for (int i = commonLength; i < b.length; ++i)
+    for (int i = commonLength; i < b.length; i += 1)
       result.add(b[i].scale(t));
     return result;
   }
diff --git a/packages/flutter/lib/src/painting/colors.dart b/packages/flutter/lib/src/painting/colors.dart
index f1e0d1f..e0a8269 100644
--- a/packages/flutter/lib/src/painting/colors.dart
+++ b/packages/flutter/lib/src/painting/colors.dart
@@ -136,9 +136,30 @@
 
   /// Linearly interpolate between two HSVColors.
   ///
+  /// The colors are interpolated by interpolating the [alpha], [hue],
+  /// [saturation], and [value] channels separately, which usually leads to a
+  /// more pleasing effect than [Color.lerp] (which interpolates the red, green,
+  /// and blue channels separately).
+  ///
   /// If either color is null, this function linearly interpolates from a
-  /// transparent instance of the other color.
+  /// transparent instance of the other color. This is usually preferable to
+  /// interpolating from [Colors.transparent] (`const Color(0x00000000)`) since
+  /// that will interpolate from a transparent red and cycle through the hues to
+  /// match the target color, regardless of what that color's hue is.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static HSVColor lerp(HSVColor a, HSVColor b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -149,7 +170,7 @@
       lerpDouble(a.alpha, b.alpha, t),
       lerpDouble(a.hue, b.hue, t),
       lerpDouble(a.saturation, b.saturation, t),
-      lerpDouble(a.value, b.value, t)
+      lerpDouble(a.value, b.value, t),
     );
   }
 
diff --git a/packages/flutter/lib/src/painting/decoration.dart b/packages/flutter/lib/src/painting/decoration.dart
index c8b22ce..e27252d 100644
--- a/packages/flutter/lib/src/painting/decoration.dart
+++ b/packages/flutter/lib/src/painting/decoration.dart
@@ -61,7 +61,8 @@
   /// Whether this decoration is complex enough to benefit from caching its painting.
   bool get isComplex => false;
 
-  /// Linearly interpolates from `a` to [this].
+  /// Linearly interpolates from another [Decoration] (which may be of a
+  /// different class) to `this`.
   ///
   /// When implementing this method in subclasses, return null if this class
   /// cannot interpolate from `a`. In that case, [lerp] will try `a`'s [lerpTo]
@@ -71,11 +72,25 @@
   /// method uses this as a fallback when two classes can't interpolate between
   /// each other.
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `this` (or something equivalent to `this`), and values in
+  /// between meaning that the interpolation is at the relevant point on the
+  /// timeline between `a` and `this`. The interpolation can be extrapolated
+  /// beyond 0.0 and 1.0, so negative values and values greater than 1.0 are
+  /// valid (and can easily be generated by curves such as
+  /// [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [Decoration.lerp].
   @protected
   Decoration lerpFrom(Decoration a, double t) => null;
 
-  /// Linearly interpolates from [this] to `b`.
+  /// Linearly interpolates from `this` to another [Decoration] (which may be of
+  /// a different class).
   ///
   /// This is called if `b`'s [lerpTo] did not know how to handle this class.
   ///
@@ -87,32 +102,54 @@
   /// method uses this as a fallback when two classes can't interpolate between
   /// each other.
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `this` (or something
+  /// equivalent to `this`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `this` and `b`. The interpolation can be extrapolated beyond 0.0
+  /// and 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [Decoration.lerp].
   @protected
   Decoration lerpTo(Decoration b, double t) => null;
 
-  /// Linearly interpolates from `begin` to `end`.
+  /// Linearly interpolates between two [Decoration]s.
   ///
-  /// This attempts to use [lerpFrom] and [lerpTo] on `end` and `begin`
+  /// This attempts to use [lerpFrom] and [lerpTo] on `b` and `a`
   /// respectively to find a solution. If the two values can't directly be
   /// interpolated, then the interpolation is done via null (at `t == 0.5`).
   ///
-  /// If the values aren't null, then for `t == 0.0` and `t == 1.0` the values
-  /// `begin` and `end` are return verbatim.
-  static Decoration lerp(Decoration begin, Decoration end, double t) {
-    if (begin == null && end == null)
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static Decoration lerp(Decoration a, Decoration b, double t) {
+    assert(t != null);
+    if (a == null && b == null)
       return null;
-    if (begin == null)
-      return end.lerpFrom(null, t) ?? end;
-    if (end == null)
-      return begin.lerpTo(null, t) ?? begin;
+    if (a == null)
+      return b.lerpFrom(null, t) ?? b;
+    if (b == null)
+      return a.lerpTo(null, t) ?? a;
     if (t == 0.0)
-      return begin;
+      return a;
     if (t == 1.0)
-      return end;
-    return end.lerpFrom(begin, t)
-        ?? begin.lerpTo(end, t)
-        ?? (t < 0.5 ? begin.lerpTo(null, t * 2.0) : end.lerpFrom(null, (t - 0.5) * 2.0));
+      return b;
+    return b.lerpFrom(a, t)
+        ?? a.lerpTo(b, t)
+        ?? (t < 0.5 ? (a.lerpTo(null, t * 2.0) ?? a) : (b.lerpFrom(null, (t - 0.5) * 2.0) ?? b));
   }
 
   /// Tests whether the given point, on a rectangle of a given size,
diff --git a/packages/flutter/lib/src/painting/edge_insets.dart b/packages/flutter/lib/src/painting/edge_insets.dart
index 7da8363..652dc06 100644
--- a/packages/flutter/lib/src/painting/edge_insets.dart
+++ b/packages/flutter/lib/src/painting/edge_insets.dart
@@ -189,7 +189,20 @@
   /// this is not reflected in the type system). Otherwise, an object
   /// representing a combination of both is returned. That object can be turned
   /// into a concrete [EdgeInsets] using [resolve].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static EdgeInsetsGeometry lerp(EdgeInsetsGeometry a, EdgeInsetsGeometry b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -206,7 +219,7 @@
       ui.lerpDouble(a._start, b._start, t),
       ui.lerpDouble(a._end, b._end, t),
       ui.lerpDouble(a._top, b._top, t),
-      ui.lerpDouble(a._bottom, b._bottom, t)
+      ui.lerpDouble(a._bottom, b._bottom, t),
     );
   }
 
@@ -542,7 +555,20 @@
   /// Linearly interpolate between two [EdgeInsets].
   ///
   /// If either is null, this function interpolates from [EdgeInsets.zero].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static EdgeInsets lerp(EdgeInsets a, EdgeInsets b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -763,7 +789,20 @@
   /// To interpolate between two [EdgeInsetsGeometry] objects of arbitrary type
   /// (either [EdgeInsets] or [EdgeInsetsDirectional]), consider the
   /// [EdgeInsetsGeometry.lerp] static method.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static EdgeInsetsDirectional lerp(EdgeInsetsDirectional a, EdgeInsetsDirectional b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart
index 9675c41..29e0b55 100644
--- a/packages/flutter/lib/src/painting/flutter_logo.dart
+++ b/packages/flutter/lib/src/painting/flutter_logo.dart
@@ -125,13 +125,25 @@
   ///
   /// If both values are null, this returns null. Otherwise, it returns a
   /// non-null value. If one of the values is null, then the result is obtained
-  /// by scaling the other value's opacity and [margin]. If neither value is
-  /// null and `t == 0.0`, then `a` is returned unmodified; if `t == 1.0` then
-  /// `b` is returned unmodified. Otherwise, the values are computed by
-  /// interpolating the properties appropriately.
+  /// by scaling the other value's opacity and [margin].
   ///
-  /// See also [Decoration.lerp].
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
+  /// See also:
+  ///
+  ///  * [Decoration.lerp], which interpolates between arbitrary decorations.
   static FlutterLogoDecoration lerp(FlutterLogoDecoration a, FlutterLogoDecoration b, double t) {
+    assert(t != null);
     assert(a == null || a.debugAssertIsValid());
     assert(b == null || b.debugAssertIsValid());
     if (a == null && b == null)
diff --git a/packages/flutter/lib/src/painting/fractional_offset.dart b/packages/flutter/lib/src/painting/fractional_offset.dart
index 3a97436..0c023fa 100644
--- a/packages/flutter/lib/src/painting/fractional_offset.dart
+++ b/packages/flutter/lib/src/painting/fractional_offset.dart
@@ -177,7 +177,20 @@
   /// Linearly interpolate between two [FractionalOffset]s.
   ///
   /// If either is null, this function interpolates from [FractionalOffset.center].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static FractionalOffset lerp(FractionalOffset a, FractionalOffset b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart
index d10edd8..2699ca4 100644
--- a/packages/flutter/lib/src/painting/gradient.dart
+++ b/packages/flutter/lib/src/painting/gradient.dart
@@ -67,7 +67,7 @@
   /// Typically this is the same as interpolating from null (with [lerp]).
   Gradient scale(double factor);
 
-  /// Linearly interpolates from `a` to [this].
+  /// Linearly interpolates from another [Gradient] to `this`.
   ///
   /// When implementing this method in subclasses, return null if this class
   /// cannot interpolate from `a`. In that case, [lerp] will try `a`'s [lerpTo]
@@ -76,6 +76,19 @@
   /// If `a` is null, this must not return null. The base class implements this
   /// by deferring to [scale].
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `this` (or something equivalent to `this`), and values in
+  /// between meaning that the interpolation is at the relevant point on the
+  /// timeline between `a` and `this`. The interpolation can be extrapolated
+  /// beyond 0.0 and 1.0, so negative values and values greater than 1.0 are
+  /// valid (and can easily be generated by curves such as
+  /// [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [Gradient.lerp].
   @protected
   Gradient lerpFrom(Gradient a, double t) {
@@ -84,7 +97,7 @@
     return null;
   }
 
-  /// Linearly interpolates from [this] to `b`.
+  /// Linearly interpolates from `this` to another [Gradient].
   ///
   /// This is called if `b`'s [lerpTo] did not know how to handle this class.
   ///
@@ -95,6 +108,18 @@
   /// If `b` is null, this must not return null. The base class implements this
   /// by deferring to [scale].
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `this` (or something
+  /// equivalent to `this`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `this` and `b`. The interpolation can be extrapolated beyond 0.0
+  /// and 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// Instead of calling this directly, use [Gradient.lerp].
   @protected
   Gradient lerpTo(Gradient b, double t) {
@@ -103,24 +128,37 @@
     return null;
   }
 
-  /// Linearly interpolates from `begin` to `end`.
+  /// Linearly interpolates between two [Gradient]s.
   ///
-  /// This defers to `end`'s [lerpTo] function if `end` is not null. If `end` is
-  /// null or if its [lerpTo] returns null, it uses `begin`'s [lerpFrom]
-  /// function instead. If both return null, it returns `begin` before `t=0.5`
-  /// and `end` after `t=0.5`.
-  static Gradient lerp(Gradient begin, Gradient end, double t) {
+  /// This defers to `b`'s [lerpTo] function if `b` is not null. If `b` is
+  /// null or if its [lerpTo] returns null, it uses `a`'s [lerpFrom]
+  /// function instead. If both return null, it returns `a` before `t == 0.5`
+  /// and `b` after `t == 0.5`.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static Gradient lerp(Gradient a, Gradient b, double t) {
+    assert(t != null);
     Gradient result;
-    if (end != null)
-      result = end.lerpFrom(begin, t); // if begin is null, this must return non-null
-    if (result == null && begin != null)
-      result = begin.lerpTo(end, t); // if end is null, this must return non-null
+    if (b != null)
+      result = b.lerpFrom(a, t); // if a is null, this must return non-null
+    if (result == null && a != null)
+      result = a.lerpTo(b, t); // if b is null, this must return non-null
     if (result != null)
       return result;
-    if (begin == null && end == null)
+    if (a == null && b == null)
       return null;
-    assert(begin != null && end != null);
-    return t < 0.5 ? begin.scale(1.0 - (t * 2.0)) : end.scale((t - 0.5) * 2.0);
+    assert(a != null && b != null);
+    return t < 0.5 ? a.scale(1.0 - (t * 2.0)) : b.scale((t - 0.5) * 2.0);
   }
 }
 
@@ -298,7 +336,20 @@
   /// [tileMode] and with the same [colors] but transparent (using [scale]).
   ///
   /// If neither gradient is null, they must have the same number of [colors].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -532,7 +583,20 @@
   /// [tileMode] and with the same [colors] but transparent (using [scale]).
   ///
   /// If neither gradient is null, they must have the same number of [colors].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static RadialGradient lerp(RadialGradient a, RadialGradient b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart
index 0321307..a01ab02 100644
--- a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart
+++ b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart
@@ -55,6 +55,7 @@
 
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
+    assert(t != null);
     if (a is RoundedRectangleBorder) {
       return new RoundedRectangleBorder(
         side: BorderSide.lerp(a.side, side, t),
@@ -73,6 +74,7 @@
 
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
+    assert(t != null);
     if (b is RoundedRectangleBorder) {
       return new RoundedRectangleBorder(
         side: BorderSide.lerp(side, b.side, t),
@@ -169,6 +171,7 @@
 
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
+    assert(t != null);
     if (a is RoundedRectangleBorder) {
       return new _RoundedRectangleToCircleBorder(
         side: BorderSide.lerp(a.side, side, t),
diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart
index f48c4ea..7aaff49 100644
--- a/packages/flutter/lib/src/painting/shape_decoration.dart
+++ b/packages/flutter/lib/src/painting/shape_decoration.dart
@@ -186,13 +186,22 @@
   /// Interpolates each parameter of the decoration separately.
   ///
   /// If both values are null, this returns null. Otherwise, it returns a
-  /// non-null value. If neither value is null and `t == 0.0`, then `a` is
-  /// returned unmodified; if `t == 1.0` then `b` is returned unmodified.
-  /// Otherwise, the values are computed by interpolating the properties
-  /// appropriately, treating a null argument like a [ShapeDecoration] whose
+  /// non-null value, with null arguments treated like a [ShapeDecoration] whose
   /// fields are all null (including the [shape], which cannot normally be
   /// null).
   ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
   /// See also:
   ///
   ///  * [Decoration.lerp], which can interpolate between any two types of
@@ -201,6 +210,7 @@
   ///    and which use [ShapeDecoration.lerp] when interpolating two
   ///    [ShapeDecoration]s or a [ShapeDecoration] to or from null.
   static ShapeDecoration lerp(ShapeDecoration a, ShapeDecoration b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a != null && b != null) {
diff --git a/packages/flutter/lib/src/painting/stadium_border.dart b/packages/flutter/lib/src/painting/stadium_border.dart
index 0223e1f..c4422a9 100644
--- a/packages/flutter/lib/src/painting/stadium_border.dart
+++ b/packages/flutter/lib/src/painting/stadium_border.dart
@@ -41,6 +41,7 @@
 
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
+    assert(t != null);
     if (a is StadiumBorder)
       return new StadiumBorder(side: BorderSide.lerp(a.side, side, t));
     if (a is CircleBorder) {
@@ -61,6 +62,7 @@
 
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
+    assert(t != null);
     if (b is StadiumBorder)
       return new StadiumBorder(side: BorderSide.lerp(side, b.side, t));
     if (b is CircleBorder) {
@@ -151,6 +153,7 @@
 
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
+    assert(t != null);
     if (a is StadiumBorder) {
       return new _StadiumToCircleBorder(
         side: BorderSide.lerp(a.side, side, t),
@@ -174,6 +177,7 @@
 
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
+    assert(t != null);
     if (b is StadiumBorder) {
       return new _StadiumToCircleBorder(
         side: BorderSide.lerp(side, b.side, t),
@@ -303,6 +307,7 @@
 
   @override
   ShapeBorder lerpFrom(ShapeBorder a, double t) {
+    assert(t != null);
     if (a is StadiumBorder) {
       return new _StadiumToRoundedRectangleBorder(
         side: BorderSide.lerp(a.side, side, t),
@@ -329,6 +334,7 @@
 
   @override
   ShapeBorder lerpTo(ShapeBorder b, double t) {
+    assert(t != null);
     if (b is StadiumBorder) {
       return new _StadiumToRoundedRectangleBorder(
         side: BorderSide.lerp(side, b.side, t),
diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart
index c39ffd1..251ecd6 100644
--- a/packages/flutter/lib/src/painting/text_style.dart
+++ b/packages/flutter/lib/src/painting/text_style.dart
@@ -338,7 +338,7 @@
     String newDebugLabel;
     assert(() {
       if (this.debugLabel != null)
-        newDebugLabel = debugLabel ?? 'copy of ${this.debugLabel}';
+        newDebugLabel = debugLabel ?? '(${this.debugLabel}).copyWith';
       return true;
     }());
     return new TextStyle(
@@ -414,7 +414,7 @@
     String modifiedDebugLabel;
     assert(() {
       if (debugLabel != null)
-        modifiedDebugLabel = 'modified $debugLabel';
+        modifiedDebugLabel = '($debugLabel).apply';
       return true;
     }());
 
@@ -459,7 +459,7 @@
     String mergedDebugLabel;
     assert(() {
       if (other.debugLabel != null || debugLabel != null)
-        mergedDebugLabel = '${other.debugLabel ?? _kDefaultDebugLabel} < ${debugLabel ?? _kDefaultDebugLabel}';
+        mergedDebugLabel = '(${debugLabel ?? _kDefaultDebugLabel}).merge(${other.debugLabel ?? _kDefaultDebugLabel})';
       return true;
     }());
 
@@ -483,29 +483,44 @@
   /// Interpolate between two text styles.
   ///
   /// This will not work well if the styles don't set the same fields.
-  static TextStyle lerp(TextStyle begin, TextStyle end, double t) {
-    assert(begin.inherit == end.inherit);
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static TextStyle lerp(TextStyle a, TextStyle b, double t) {
+    assert(a != null);
+    assert(b != null);
+    assert(t != null);
+    assert(a.inherit == b.inherit);
 
     String lerpDebugLabel;
     assert(() {
-      lerpDebugLabel = 'lerp(${begin.debugLabel ?? _kDefaultDebugLabel}, ${end.debugLabel ?? _kDefaultDebugLabel})';
+      lerpDebugLabel = 'lerp(${a.debugLabel ?? _kDefaultDebugLabel} ⎯${t.toStringAsFixed(1)}→ ${b.debugLabel ?? _kDefaultDebugLabel})';
       return true;
     }());
 
     return new TextStyle(
-      inherit: end.inherit,
-      color: Color.lerp(begin.color, end.color, t),
-      fontFamily: t < 0.5 ? begin.fontFamily : end.fontFamily,
-      fontSize: ui.lerpDouble(begin.fontSize ?? end.fontSize, end.fontSize ?? begin.fontSize, t),
-      fontWeight: FontWeight.lerp(begin.fontWeight, end.fontWeight, t),
-      fontStyle: t < 0.5 ? begin.fontStyle : end.fontStyle,
-      letterSpacing: ui.lerpDouble(begin.letterSpacing ?? end.letterSpacing, end.letterSpacing ?? begin.letterSpacing, t),
-      wordSpacing: ui.lerpDouble(begin.wordSpacing ?? end.wordSpacing, end.wordSpacing ?? begin.wordSpacing, t),
-      textBaseline: t < 0.5 ? begin.textBaseline : end.textBaseline,
-      height: ui.lerpDouble(begin.height ?? end.height, end.height ?? begin.height, t),
-      decoration: t < 0.5 ? begin.decoration : end.decoration,
-      decorationColor: Color.lerp(begin.decorationColor, end.decorationColor, t),
-      decorationStyle: t < 0.5 ? begin.decorationStyle : end.decorationStyle,
+      inherit: b.inherit,
+      color: Color.lerp(a.color, b.color, t),
+      fontFamily: t < 0.5 ? a.fontFamily : b.fontFamily,
+      fontSize: ui.lerpDouble(a.fontSize ?? b.fontSize, b.fontSize ?? a.fontSize, t),
+      fontWeight: FontWeight.lerp(a.fontWeight, b.fontWeight, t),
+      fontStyle: t < 0.5 ? a.fontStyle : b.fontStyle,
+      letterSpacing: ui.lerpDouble(a.letterSpacing ?? b.letterSpacing, b.letterSpacing ?? a.letterSpacing, t),
+      wordSpacing: ui.lerpDouble(a.wordSpacing ?? b.wordSpacing, b.wordSpacing ?? a.wordSpacing, t),
+      textBaseline: t < 0.5 ? a.textBaseline : b.textBaseline,
+      height: ui.lerpDouble(a.height ?? b.height, b.height ?? a.height, t),
+      decoration: t < 0.5 ? a.decoration : b.decoration,
+      decorationColor: Color.lerp(a.decorationColor, b.decorationColor, t),
+      decorationStyle: t < 0.5 ? a.decorationStyle : b.decorationStyle,
       debugLabel: lerpDebugLabel,
     );
   }
diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart
index b87cc89..211d8cd 100644
--- a/packages/flutter/lib/src/rendering/box.dart
+++ b/packages/flutter/lib/src/rendering/box.dart
@@ -402,7 +402,20 @@
   ///
   /// If either is null, this function interpolates from a [BoxConstraints]
   /// object whose fields are all set to 0.0.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static BoxConstraints lerp(BoxConstraints a, BoxConstraints b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart
index bcd6646..a7798b7 100644
--- a/packages/flutter/lib/src/rendering/stack.dart
+++ b/packages/flutter/lib/src/rendering/stack.dart
@@ -124,7 +124,20 @@
   /// Linearly interpolate between two RelativeRects.
   ///
   /// If either rect is null, this function interpolates from [RelativeRect.fill].
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static RelativeRect lerp(RelativeRect a, RelativeRect b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -137,7 +150,7 @@
       lerpDouble(a.left, b.left, t),
       lerpDouble(a.top, b.top, t),
       lerpDouble(a.right, b.right, t),
-      lerpDouble(a.bottom, b.bottom, t)
+      lerpDouble(a.bottom, b.bottom, t),
     );
   }
 
diff --git a/packages/flutter/lib/src/rendering/table_border.dart b/packages/flutter/lib/src/rendering/table_border.dart
index fdf13e1..8f9c008 100644
--- a/packages/flutter/lib/src/rendering/table_border.dart
+++ b/packages/flutter/lib/src/rendering/table_border.dart
@@ -116,15 +116,29 @@
     return true;
   }
 
-  /// Creates a new border with the widths of this border multiplied by `t`.
+  /// Creates a copy of this border but with the widths scaled by the factor `t`.
+  ///
+  /// The `t` argument represents the multiplicand, or the position on the
+  /// timeline for an interpolation from nothing to `this`, with 0.0 meaning
+  /// that the the object returned should be the nil variant of this object, 1.0
+  /// meaning that no change should be applied, returning `this` (or something
+  /// equivalent to `this`), and other values meaning that the object should be
+  /// multiplied by `t`. Negative values are treated like zero.
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  ///
+  /// See also:
+  ///
+  ///  * [BorderSide.scale], which is used to implement this method.
   TableBorder scale(double t) {
     return new TableBorder(
-      top: top.copyWith(width: t * top.width),
-      right: right.copyWith(width: t * right.width),
-      bottom: bottom.copyWith(width: t * bottom.width),
-      left: left.copyWith(width: t * left.width),
-      horizontalInside: horizontalInside.copyWith(width: t * horizontalInside.width),
-      verticalInside: verticalInside.copyWith(width: t * verticalInside.width)
+      top: top.scale(t),
+      right: right.scale(t),
+      bottom: bottom.scale(t),
+      left: left.scale(t),
+      horizontalInside: horizontalInside.scale(t),
+      verticalInside: verticalInside.scale(t),
     );
   }
 
@@ -132,7 +146,20 @@
   ///
   /// If a border is null, it is treated as having only [BorderSide.none]
   /// borders.
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
   static TableBorder lerp(TableBorder a, TableBorder b, double t) {
+    assert(t != null);
     if (a == null && b == null)
       return null;
     if (a == null)
@@ -145,7 +172,7 @@
       bottom: BorderSide.lerp(a.bottom, b.bottom, t),
       left: BorderSide.lerp(a.left, b.left, t),
       horizontalInside: BorderSide.lerp(a.horizontalInside, b.horizontalInside, t),
-      verticalInside: BorderSide.lerp(a.verticalInside, b.verticalInside, t)
+      verticalInside: BorderSide.lerp(a.verticalInside, b.verticalInside, t),
     );
   }
 
diff --git a/packages/flutter/lib/src/widgets/icon_theme_data.dart b/packages/flutter/lib/src/widgets/icon_theme_data.dart
index 06a9847..0dc5f41 100644
--- a/packages/flutter/lib/src/widgets/icon_theme_data.dart
+++ b/packages/flutter/lib/src/widgets/icon_theme_data.dart
@@ -65,11 +65,24 @@
   final double size;
 
   /// Linearly interpolate between two icon theme data objects.
-  static IconThemeData lerp(IconThemeData begin, IconThemeData end, double t) {
+  ///
+  /// The `t` argument represents position on the timeline, with 0.0 meaning
+  /// that the interpolation has not started, returning `a` (or something
+  /// equivalent to `a`), 1.0 meaning that the interpolation has finished,
+  /// returning `b` (or something equivalent to `b`), and values in between
+  /// meaning that the interpolation is at the relevant point on the timeline
+  /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and
+  /// 1.0, so negative values and values greater than 1.0 are valid (and can
+  /// easily be generated by curves such as [Curves.elasticInOut]).
+  ///
+  /// Values for `t` are usually obtained from an [Animation<double>], such as
+  /// an [AnimationController].
+  static IconThemeData lerp(IconThemeData a, IconThemeData b, double t) {
+    assert(t != null);
     return new IconThemeData(
-      color: Color.lerp(begin.color, end.color, t),
-      opacity: ui.lerpDouble(begin.opacity, end.opacity, t),
-      size: ui.lerpDouble(begin.size, end.size, t)
+      color: Color.lerp(a.color, b.color, t),
+      opacity: ui.lerpDouble(a.opacity, b.opacity, t),
+      size: ui.lerpDouble(a.size, b.size, t),
     );
   }
 
diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart
index 926f901..fbfa0af 100644
--- a/packages/flutter/test/material/theme_test.dart
+++ b/packages/flutter/test/material/theme_test.dart
@@ -417,7 +417,7 @@
       }
     }
 
-    expect(theme.textTheme.display4.debugLabel, 'blackMountainView display4 < englishLike display4');
+    expect(theme.textTheme.display4.debugLabel, '(englishLike display4).merge(blackMountainView display4)');
   });
 }
 
diff --git a/packages/flutter/test/painting/text_style_test.dart b/packages/flutter/test/painting/text_style_test.dart
index fd2f607..f6c1ff9 100644
--- a/packages/flutter/test/painting/text_style_test.dart
+++ b/packages/flutter/test/painting/text_style_test.dart
@@ -156,11 +156,11 @@
 
     expect(foo.debugLabel, 'foo');
     expect(foo.toString(), 'TextStyle(debugLabel: foo, inherit: true, size: 1.0)');
-    expect(foo.merge(bar).debugLabel, 'bar < foo');
-    expect(foo.merge(bar).merge(baz).debugLabel, 'baz < bar < foo');
-    expect(foo.copyWith().debugLabel, 'copy of foo');
-    expect(foo.apply().debugLabel, 'modified foo');
-    expect(TextStyle.lerp(foo, bar, 0.5).debugLabel, 'lerp(foo, bar)');
-    expect(TextStyle.lerp(foo.merge(bar), baz, 0.5).copyWith().debugLabel, 'copy of lerp(bar < foo, baz)');
+    expect(foo.merge(bar).debugLabel, '(foo).merge(bar)');
+    expect(foo.merge(bar).merge(baz).debugLabel, '((foo).merge(bar)).merge(baz)');
+    expect(foo.copyWith().debugLabel, '(foo).copyWith');
+    expect(foo.apply().debugLabel, '(foo).apply');
+    expect(TextStyle.lerp(foo, bar, 0.5).debugLabel, 'lerp(foo ⎯0.5→ bar)');
+    expect(TextStyle.lerp(foo.merge(bar), baz, 0.51).copyWith().debugLabel, '(lerp((foo).merge(bar) ⎯0.5→ baz)).copyWith');
   });
 }
diff --git a/packages/flutter/test/rendering/table_border_test.dart b/packages/flutter/test/rendering/table_border_test.dart
index 6e9d717..4357c12 100644
--- a/packages/flutter/test/rendering/table_border_test.dart
+++ b/packages/flutter/test/rendering/table_border_test.dart
@@ -57,8 +57,8 @@
     expect(border3.dimensions, const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0));
     expect(border3.isUniform, isFalse);
     expect(border3.scale(0.0), new TableBorder.symmetric(
-      inside: const BorderSide(width: 0.0),
-      outside: const BorderSide(width: 0.0, color: const Color(0xFFFF0000)),
+      inside: const BorderSide(width: 0.0, style: BorderStyle.none),
+      outside: const BorderSide(width: 0.0, color: const Color(0xFFFF0000), style: BorderStyle.none),
     ));
   });