Allow symbols to be used in compile-time expressions.
diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h
index ae3fac3..ae6373d 100644
--- a/Eigen/src/Core/ArithmeticSequence.h
+++ b/Eigen/src/Core/ArithmeticSequence.h
@@ -61,26 +61,28 @@
 template <typename FirstType, typename SizeType, typename IncrType>
 class ArithmeticSequence {
  public:
-  ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
-  ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {}
+  constexpr ArithmeticSequence() = default;
+  constexpr ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
+  constexpr ArithmeticSequence(FirstType first, SizeType size, IncrType incr)
+      : m_first(first), m_size(size), m_incr(incr) {}
 
   enum {
-    SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
+    // SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
     IncrAtCompileTime = internal::get_fixed_value<IncrType, DynamicIndex>::value
   };
 
   /** \returns the size, i.e., number of elements, of the sequence */
-  Index size() const { return m_size; }
+  constexpr Index size() const { return m_size; }
 
   /** \returns the first element \f$ a_0 \f$ in the sequence */
-  Index first() const { return m_first; }
+  constexpr Index first() const { return m_first; }
 
   /** \returns the value \f$ a_i \f$ at index \a i in the sequence. */
-  Index operator[](Index i) const { return m_first + i * m_incr; }
+  constexpr Index operator[](Index i) const { return m_first + i * m_incr; }
 
-  const FirstType& firstObject() const { return m_first; }
-  const SizeType& sizeObject() const { return m_size; }
-  const IncrType& incrObject() const { return m_incr; }
+  constexpr const FirstType& firstObject() const { return m_first; }
+  constexpr const SizeType& sizeObject() const { return m_size; }
+  constexpr const IncrType& incrObject() const { return m_incr; }
 
  protected:
   FirstType m_first;
@@ -88,7 +90,7 @@
   IncrType m_incr;
 
  public:
-  auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) {
+  constexpr auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) {
     return seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr);
   }
 };
@@ -201,38 +203,6 @@
 
 }  // namespace placeholders
 
-namespace internal {
-
-// Convert a symbolic span into a usable one (i.e., remove last/end "keywords")
-template <typename T>
-struct make_size_type {
-  typedef std::conditional_t<symbolic::is_symbolic<T>::value, Index, T> type;
-};
-
-template <typename FirstType, typename SizeType, typename IncrType, int XprSize>
-struct IndexedViewCompatibleType<ArithmeticSequence<FirstType, SizeType, IncrType>, XprSize> {
-  typedef ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> type;
-};
-
-template <typename FirstType, typename SizeType, typename IncrType>
-ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> makeIndexedViewCompatible(
-    const ArithmeticSequence<FirstType, SizeType, IncrType>& ids, Index size, SpecializedType) {
-  return ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType>(
-      eval_expr_given_size(ids.firstObject(), size), eval_expr_given_size(ids.sizeObject(), size), ids.incrObject());
-}
-
-template <typename FirstType, typename SizeType, typename IncrType>
-struct get_compile_time_incr<ArithmeticSequence<FirstType, SizeType, IncrType> > {
-  enum { value = get_fixed_value<IncrType, DynamicIndex>::value };
-};
-
-template <typename FirstType, typename SizeType, typename IncrType>
-constexpr Index get_runtime_incr(const ArithmeticSequence<FirstType, SizeType, IncrType>& x) EIGEN_NOEXCEPT {
-  return static_cast<Index>(x.incrObject());
-}
-
-}  // end namespace internal
-
 /** \namespace Eigen::indexing
   * \ingroup Core_Module
   *
diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h
index b90ecb1..454e560 100644
--- a/Eigen/src/Core/IndexedView.h
+++ b/Eigen/src/Core/IndexedView.h
@@ -20,8 +20,8 @@
 template <typename XprType, typename RowIndices, typename ColIndices>
 struct traits<IndexedView<XprType, RowIndices, ColIndices>> : traits<XprType> {
   enum {
-    RowsAtCompileTime = int(array_size<RowIndices>::value),
-    ColsAtCompileTime = int(array_size<ColIndices>::value),
+    RowsAtCompileTime = int(IndexedViewHelper<RowIndices>::SizeAtCompileTime),
+    ColsAtCompileTime = int(IndexedViewHelper<ColIndices>::SizeAtCompileTime),
     MaxRowsAtCompileTime = RowsAtCompileTime,
     MaxColsAtCompileTime = ColsAtCompileTime,
 
@@ -30,8 +30,8 @@
                  : (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0
                                                                             : XprTypeIsRowMajor,
 
-    RowIncr = int(get_compile_time_incr<RowIndices>::value),
-    ColIncr = int(get_compile_time_incr<ColIndices>::value),
+    RowIncr = int(IndexedViewHelper<RowIndices>::IncrAtCompileTime),
+    ColIncr = int(IndexedViewHelper<ColIndices>::IncrAtCompileTime),
     InnerIncr = IsRowMajor ? ColIncr : RowIncr,
     OuterIncr = IsRowMajor ? RowIncr : ColIncr,
 
@@ -47,24 +47,23 @@
                     is_same<AllRange<InnerSize>, std::conditional_t<XprTypeIsRowMajor, ColIndices, RowIndices>>::value,
 
     InnerStrideAtCompileTime =
-        InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == UndefinedIncr
+        InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == Undefined
             ? Dynamic
             : XprInnerStride * InnerIncr,
     OuterStrideAtCompileTime =
-        OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == UndefinedIncr
+        OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == Undefined
             ? Dynamic
             : XprOuterstride * OuterIncr,
 
-    ReturnAsScalar = is_same<RowIndices, SingleRange>::value && is_same<ColIndices, SingleRange>::value,
+    ReturnAsScalar = is_single_range<RowIndices>::value && is_single_range<ColIndices>::value,
     ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike,
     ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock),
 
     // FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag,
     // but this is too strict regarding negative strides...
-    DirectAccessMask =
-        (int(InnerIncr) != UndefinedIncr && int(OuterIncr) != UndefinedIncr && InnerIncr >= 0 && OuterIncr >= 0)
-            ? DirectAccessBit
-            : 0,
+    DirectAccessMask = (int(InnerIncr) != Undefined && int(OuterIncr) != Undefined && InnerIncr >= 0 && OuterIncr >= 0)
+                           ? DirectAccessBit
+                           : 0,
     FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
     FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0,
     FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0,
@@ -153,10 +152,10 @@
       : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {}
 
   /** \returns number of rows */
-  Index rows() const { return internal::index_list_size(m_rowIndices); }
+  Index rows() const { return IndexedViewHelper<RowIndices>::size(m_rowIndices); }
 
   /** \returns number of columns */
-  Index cols() const { return internal::index_list_size(m_colIndices); }
+  Index cols() const { return IndexedViewHelper<ColIndices>::size(m_colIndices); }
 
   /** \returns the nested expression */
   const internal::remove_all_t<XprType>& nestedExpression() const { return m_xpr; }
@@ -198,16 +197,16 @@
   IndexedViewImpl(XprType& xpr, const T0& rowIndices, const T1& colIndices) : Base(xpr, rowIndices, colIndices) {}
 
   Index rowIncrement() const {
-    if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != UndefinedIncr) {
+    if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != Undefined) {
       return traits<Derived>::RowIncr;
     }
-    return get_runtime_incr(this->rowIndices());
+    return IndexedViewHelper<RowIndices>::incr(this->rowIndices());
   }
   Index colIncrement() const {
-    if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != UndefinedIncr) {
+    if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != Undefined) {
       return traits<Derived>::ColIncr;
     }
-    return get_runtime_incr(this->colIndices());
+    return IndexedViewHelper<ColIndices>::incr(this->colIndices());
   }
 
   Index innerIncrement() const { return traits<Derived>::IsRowMajor ? colIncrement() : rowIncrement(); }
diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h
index 8b06c67..9f4a2d8 100644
--- a/Eigen/src/Core/util/Constants.h
+++ b/Eigen/src/Core/util/Constants.h
@@ -29,9 +29,9 @@
  */
 const int DynamicIndex = 0xffffff;
 
-/** This value means that the increment to go from one value to another in a sequence is not constant for each step.
+/** This value means that the requested value is not defined.
  */
-const int UndefinedIncr = 0xfffffe;
+const int Undefined = 0xfffffe;
 
 /** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>().
  * The value Infinity there means the L-infinity norm.
diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h
index c312939..2f2ba9b 100644
--- a/Eigen/src/Core/util/ForwardDeclarations.h
+++ b/Eigen/src/Core/util/ForwardDeclarations.h
@@ -91,6 +91,8 @@
 class IndexedView;
 template <typename XprType, int Rows = Dynamic, int Cols = Dynamic, int Order = 0>
 class Reshaped;
+template <typename FirstType, typename SizeType, typename IncrType>
+class ArithmeticSequence;
 
 template <typename MatrixType, int Size = Dynamic>
 class VectorBlock;
diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h
index 9d1b348..c187002 100644
--- a/Eigen/src/Core/util/IndexedViewHelper.h
+++ b/Eigen/src/Core/util/IndexedViewHelper.h
@@ -17,6 +17,9 @@
 
 namespace internal {
 struct symbolic_last_tag {};
+
+struct all_t {};
+
 }  // namespace internal
 
 namespace placeholders {
@@ -42,131 +45,7 @@
  *
  * \sa end
  */
-static const last_t last;
-
-}  // namespace placeholders
-
-namespace internal {
-
-// Replace symbolic last/end "keywords" by their true runtime value
-inline Index eval_expr_given_size(Index x, Index /* size */) { return x; }
-
-template <int N>
-FixedInt<N> eval_expr_given_size(FixedInt<N> x, Index /*size*/) {
-  return x;
-}
-
-template <typename Derived>
-Index eval_expr_given_size(const symbolic::BaseExpr<Derived>& x, Index size) {
-  return x.derived().eval(Eigen::placeholders::last = size - 1);
-}
-
-// Extract increment/step at compile time
-template <typename T, typename EnableIf = void>
-struct get_compile_time_incr {
-  enum { value = UndefinedIncr };
-};
-
-template <typename T>
-constexpr Index get_runtime_incr(const T&) EIGEN_NOEXCEPT {
-  return Index(1);
-}
-
-// Analogue of std::get<0>(x), but tailored for our needs.
-template <typename T>
-EIGEN_CONSTEXPR Index first(const T& x) EIGEN_NOEXCEPT {
-  return x.first();
-}
-
-// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by
-// MatrixSlice The generic implementation is a no-op
-template <typename T, int XprSize, typename EnableIf = void>
-struct IndexedViewCompatibleType {
-  typedef T type;
-};
-
-template <typename T, typename Q>
-const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) {
-  return x;
-}
-
-//--------------------------------------------------------------------------------
-// Handling of a single Index
-//--------------------------------------------------------------------------------
-
-struct SingleRange {
-  enum { SizeAtCompileTime = 1 };
-  SingleRange(Index val) : m_value(val) {}
-  Index operator[](Index) const { return m_value; }
-  static EIGEN_CONSTEXPR Index size() EIGEN_NOEXCEPT { return 1; }
-  Index first() const EIGEN_NOEXCEPT { return m_value; }
-  Index m_value;
-};
-
-template <>
-struct get_compile_time_incr<SingleRange> {
-  enum { value = 1 };  // 1 or 0 ??
-};
-
-// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operator[](int)
-// methods)
-template <typename T, int XprSize>
-struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<internal::is_integral<T>::value>> {
-  // Here we could simply use Array, but maybe it's less work for the compiler to use
-  // a simpler wrapper as SingleRange
-  // typedef Eigen::Array<Index,1,1> type;
-  typedef SingleRange type;
-};
-
-template <typename T, int XprSize>
-struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<symbolic::is_symbolic<T>::value>> {
-  typedef SingleRange type;
-};
-
-template <typename T>
-std::enable_if_t<symbolic::is_symbolic<T>::value, SingleRange> makeIndexedViewCompatible(const T& id, Index size,
-                                                                                         SpecializedType) {
-  return eval_expr_given_size(id, size);
-}
-
-//--------------------------------------------------------------------------------
-// Handling of all
-//--------------------------------------------------------------------------------
-
-struct all_t {
-  all_t() {}
-};
-
-// Convert a symbolic 'all' into a usable range type
-template <int XprSize>
-struct AllRange {
-  enum { SizeAtCompileTime = XprSize };
-  AllRange(Index size = XprSize) : m_size(size) {}
-  EIGEN_CONSTEXPR Index operator[](Index i) const EIGEN_NOEXCEPT { return i; }
-  EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_size.value(); }
-  EIGEN_CONSTEXPR Index first() const EIGEN_NOEXCEPT { return 0; }
-  variable_if_dynamic<Index, XprSize> m_size;
-};
-
-template <int XprSize>
-struct IndexedViewCompatibleType<all_t, XprSize> {
-  typedef AllRange<XprSize> type;
-};
-
-template <typename XprSizeType>
-inline AllRange<get_fixed_value<XprSizeType>::value> makeIndexedViewCompatible(all_t, XprSizeType size,
-                                                                               SpecializedType) {
-  return AllRange<get_fixed_value<XprSizeType>::value>(size);
-}
-
-template <int Size>
-struct get_compile_time_incr<AllRange<Size>> {
-  enum { value = 1 };
-};
-
-}  // end namespace internal
-
-namespace placeholders {
+static constexpr const last_t last;
 
 typedef symbolic::AddExpr<symbolic::SymbolExpr<internal::symbolic_last_tag>,
                           symbolic::ValueExpr<Eigen::internal::FixedInt<1>>>
@@ -186,28 +65,251 @@
  * \sa last
  */
 #ifdef EIGEN_PARSED_BY_DOXYGEN
-static const auto lastp1 = last + fix<1>;
+static constexpr auto lastp1 = last + fix<1>;
 #else
 // Using a FixedExpr<1> expression is important here to make sure the compiler
 // can fully optimize the computation starting indices with zero overhead.
-static const lastp1_t lastp1(last + fix<1>());
+static constexpr lastp1_t lastp1(last + fix<1>());
 #endif
 
 /** \var end
  * \ingroup Core_Module
  * \sa lastp1
  */
-static const lastp1_t end = lastp1;
+static constexpr lastp1_t end = lastp1;
 
 /** \var all
  * \ingroup Core_Module
  * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or
  * columns
  */
-static const Eigen::internal::all_t all;
+static constexpr Eigen::internal::all_t all;
 
 }  // namespace placeholders
 
+namespace internal {
+
+// Evaluate a symbolic expression or constant given the "size" of an object, allowing
+// any symbols like `last` to be evaluated.  The default here assumes a dynamic constant.
+template <typename Expr, int SizeAtCompileTime, typename EnableIf = void>
+struct SymbolicExpressionEvaluator {
+  static constexpr Index ValueAtCompileTime = Undefined;
+  static Index eval(const Expr& expr, Index /*size*/) { return static_cast<Index>(expr); }
+};
+
+// Symbolic expression with size known at compile-time.
+template <typename Expr, int SizeAtCompileTime>
+struct SymbolicExpressionEvaluator<Expr, SizeAtCompileTime, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
+  static constexpr Index ValueAtCompileTime =
+      Expr::Derived::eval_at_compile_time(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
+  static Index eval(const Expr& expr, Index /*size*/) {
+    return expr.eval(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>);
+  }
+};
+
+// Symbolic expression with dynamic size.
+template <typename Expr>
+struct SymbolicExpressionEvaluator<Expr, Dynamic, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> {
+  static constexpr Index ValueAtCompileTime = Undefined;
+  static Index eval(const Expr& expr, Index size) { return expr.eval(Eigen::placeholders::last = size - 1); }
+};
+
+// Fixed int.
+template <int N, int SizeAtCompileTime>
+struct SymbolicExpressionEvaluator<FixedInt<N>, SizeAtCompileTime, void> {
+  static constexpr Index ValueAtCompileTime = static_cast<Index>(N);
+  static Index eval(const FixedInt<N>& /*expr*/, Index /*size*/) { return ValueAtCompileTime; }
+};
+
+//--------------------------------------------------------------------------------
+// Handling of generic indices (e.g. array)
+//--------------------------------------------------------------------------------
+
+// Potentially wrap indices in a type that is better-suited for IndexedView evaluation.
+template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void>
+struct IndexedViewHelperIndicesWrapper {
+  using type = Indices;
+  static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; }
+};
+
+// Extract compile-time and runtime first, size, increments.
+template <typename Indices, typename EnableIf = void>
+struct IndexedViewHelper {
+  static constexpr Index FirstAtCompileTime = Undefined;
+  static constexpr Index SizeAtCompileTime = array_size<Indices>::value;
+  static constexpr Index IncrAtCompileTime = Undefined;
+
+  static constexpr Index first(const Indices& indices) { return static_cast<Index>(indices[0]); }
+  static constexpr Index size(const Indices& indices) { return index_list_size(indices); }
+  static constexpr Index incr(const Indices& /*indices*/) { return Undefined; }
+};
+
+//--------------------------------------------------------------------------------
+// Handling of ArithmeticSequence
+//--------------------------------------------------------------------------------
+
+template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
+class ArithmeticSequenceRange {
+ public:
+  static constexpr Index FirstAtCompileTime = FirstAtCompileTime_;
+  static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
+  static constexpr Index IncrAtCompileTime = IncrAtCompileTime_;
+
+  constexpr ArithmeticSequenceRange(Index first, Index size, Index incr) : first_{first}, size_{size}, incr_{incr} {}
+  constexpr Index operator[](Index i) const { return first() + i * incr(); }
+  constexpr Index first() const noexcept { return first_.value(); }
+  constexpr Index size() const noexcept { return size_.value(); }
+  constexpr Index incr() const noexcept { return incr_.value(); }
+
+ private:
+  variable_if_dynamicindex<Index, int(FirstAtCompileTime)> first_;
+  variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
+  variable_if_dynamicindex<Index, int(IncrAtCompileTime)> incr_;
+};
+
+template <typename FirstType, typename SizeType, typename IncrType, int NestedSizeAtCompileTime>
+struct IndexedViewHelperIndicesWrapper<ArithmeticSequence<FirstType, SizeType, IncrType>, NestedSizeAtCompileTime,
+                                       void> {
+  static constexpr Index EvalFirstAtCompileTime =
+      SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::ValueAtCompileTime;
+  static constexpr Index EvalSizeAtCompileTime =
+      SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::ValueAtCompileTime;
+  static constexpr Index EvalIncrAtCompileTime =
+      SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::ValueAtCompileTime;
+
+  static constexpr Index FirstAtCompileTime =
+      (int(EvalFirstAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalFirstAtCompileTime;
+  static constexpr Index SizeAtCompileTime =
+      (int(EvalSizeAtCompileTime) == Undefined) ? Index(Dynamic) : EvalSizeAtCompileTime;
+  static constexpr Index IncrAtCompileTime =
+      (int(EvalIncrAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalIncrAtCompileTime;
+
+  using Indices = ArithmeticSequence<FirstType, SizeType, IncrType>;
+  using type = ArithmeticSequenceRange<FirstAtCompileTime, SizeAtCompileTime, IncrAtCompileTime>;
+
+  static type CreateIndexSequence(const Indices& indices, Index nested_size) {
+    Index first =
+        SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::eval(indices.firstObject(), nested_size);
+    Index size =
+        SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::eval(indices.sizeObject(), nested_size);
+    Index incr =
+        SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::eval(indices.incrObject(), nested_size);
+    return type(first, size, incr);
+  }
+};
+
+template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_>
+struct IndexedViewHelper<ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>, void> {
+ public:
+  using Indices = ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>;
+  static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
+  static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
+  static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
+  static Index first(const Indices& indices) { return indices.first(); }
+  static Index size(const Indices& indices) { return indices.size(); }
+  static Index incr(const Indices& indices) { return indices.incr(); }
+};
+
+//--------------------------------------------------------------------------------
+// Handling of a single index.
+//--------------------------------------------------------------------------------
+
+template <Index ValueAtCompileTime>
+class SingleRange {
+ public:
+  static constexpr Index FirstAtCompileTime = ValueAtCompileTime;
+  static constexpr Index SizeAtCompileTime = Index(1);
+  static constexpr Index IncrAtCompileTime = Index(1);  // Needs to be 1 to be treated as block-like.
+
+  constexpr SingleRange(Index v) noexcept : value_(v) {}
+  constexpr Index operator[](Index) const noexcept { return first(); }
+  constexpr Index first() const noexcept { return value_.value(); }
+  constexpr Index size() const noexcept { return SizeAtCompileTime; }
+  constexpr Index incr() const noexcept { return IncrAtCompileTime; }
+
+ private:
+  variable_if_dynamicindex<Index, int(ValueAtCompileTime)> value_;
+};
+
+template <typename T>
+struct is_single_range : public std::false_type {};
+
+template <Index ValueAtCompileTime>
+struct is_single_range<SingleRange<ValueAtCompileTime>> : public std::true_type {};
+
+template <typename SingleIndex, int NestedSizeAtCompileTime>
+struct IndexedViewHelperIndicesWrapper<
+    SingleIndex, NestedSizeAtCompileTime,
+    std::enable_if_t<std::is_integral<SingleIndex>::value || symbolic::is_symbolic<SingleIndex>::value>> {
+  static constexpr Index EvalValueAtCompileTime =
+      SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::ValueAtCompileTime;
+  static constexpr Index ValueAtCompileTime =
+      (int(EvalValueAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalValueAtCompileTime;
+  using type = SingleRange<ValueAtCompileTime>;
+  static type CreateIndexSequence(const SingleIndex& index, Index nested_size) {
+    return type(SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::eval(index, nested_size));
+  }
+};
+
+template <int N, int NestedSizeAtCompileTime>
+struct IndexedViewHelperIndicesWrapper<FixedInt<N>, NestedSizeAtCompileTime, void> {
+  using type = SingleRange<Index(N)>;
+  static type CreateIndexSequence(const FixedInt<N>& /*index*/) { return type(Index(N)); }
+};
+
+template <Index ValueAtCompileTime>
+struct IndexedViewHelper<SingleRange<ValueAtCompileTime>, void> {
+  using Indices = SingleRange<ValueAtCompileTime>;
+  static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
+  static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
+  static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
+
+  static constexpr Index first(const Indices& indices) { return indices.first(); }
+  static constexpr Index size(const Indices& /*indices*/) { return SizeAtCompileTime; }
+  static constexpr Index incr(const Indices& /*indices*/) { return IncrAtCompileTime; }
+};
+
+//--------------------------------------------------------------------------------
+// Handling of all
+//--------------------------------------------------------------------------------
+
+// Convert a symbolic 'all' into a usable range type
+template <Index SizeAtCompileTime_>
+class AllRange {
+ public:
+  static constexpr Index FirstAtCompileTime = Index(0);
+  static constexpr Index SizeAtCompileTime = SizeAtCompileTime_;
+  static constexpr Index IncrAtCompileTime = Index(1);
+  constexpr AllRange(Index size) : size_(size) {}
+  constexpr Index operator[](Index i) const noexcept { return i; }
+  constexpr Index first() const noexcept { return FirstAtCompileTime; }
+  constexpr Index size() const noexcept { return size_.value(); }
+  constexpr Index incr() const noexcept { return IncrAtCompileTime; }
+
+ private:
+  variable_if_dynamic<Index, int(SizeAtCompileTime)> size_;
+};
+
+template <int NestedSizeAtCompileTime>
+struct IndexedViewHelperIndicesWrapper<all_t, NestedSizeAtCompileTime, void> {
+  using type = AllRange<Index(NestedSizeAtCompileTime)>;
+  static type CreateIndexSequence(const all_t& /*indices*/, Index nested_size) { return type(nested_size); }
+};
+
+template <Index SizeAtCompileTime_>
+struct IndexedViewHelper<AllRange<SizeAtCompileTime_>, void> {
+  using Indices = AllRange<SizeAtCompileTime_>;
+  static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime;
+  static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime;
+  static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime;
+
+  static Index first(const Indices& indices) { return indices.first(); }
+  static Index size(const Indices& indices) { return indices.size(); }
+  static Index incr(const Indices& indices) { return indices.incr(); }
+};
+
+}  // end namespace internal
+
 }  // end namespace Eigen
 
 #endif  // EIGEN_INDEXED_VIEW_HELPER_H
diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h
index 279d553..2eb5fd9 100644
--- a/Eigen/src/Core/util/IntegralConstant.h
+++ b/Eigen/src/Core/util/IntegralConstant.h
@@ -54,65 +54,60 @@
 template <int N>
 class FixedInt {
  public:
-  static const int value = N;
-  EIGEN_CONSTEXPR operator int() const { return value; }
+  static constexpr int value = N;
+  constexpr operator int() const { return N; }
 
-  EIGEN_CONSTEXPR
-  FixedInt() = default;
+  constexpr FixedInt() = default;
+  constexpr FixedInt(std::integral_constant<int, N>) {}
 
-  EIGEN_CONSTEXPR
-  FixedInt(std::integral_constant<int, N>) {}
-
-  EIGEN_CONSTEXPR
-  FixedInt(VariableAndFixedInt<N> other) {
+  constexpr FixedInt(VariableAndFixedInt<N> other) {
 #ifndef EIGEN_INTERNAL_DEBUGGING
     EIGEN_UNUSED_VARIABLE(other);
 #endif
     eigen_internal_assert(int(other) == N);
   }
 
-  EIGEN_CONSTEXPR
-  FixedInt<-N> operator-() const { return FixedInt<-N>(); }
+  constexpr FixedInt<-N> operator-() const { return FixedInt<-N>(); }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N + M> operator+(FixedInt<M>) const {
+  constexpr FixedInt<N + M> operator+(FixedInt<M>) const {
     return FixedInt<N + M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N - M> operator-(FixedInt<M>) const {
+  constexpr FixedInt<N - M> operator-(FixedInt<M>) const {
     return FixedInt<N - M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N * M> operator*(FixedInt<M>) const {
+  constexpr FixedInt<N * M> operator*(FixedInt<M>) const {
     return FixedInt<N * M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N / M> operator/(FixedInt<M>) const {
+  constexpr FixedInt<N / M> operator/(FixedInt<M>) const {
     return FixedInt<N / M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N % M> operator%(FixedInt<M>) const {
+  constexpr FixedInt<N % M> operator%(FixedInt<M>) const {
     return FixedInt<N % M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N | M> operator|(FixedInt<M>) const {
+  constexpr FixedInt<N | M> operator|(FixedInt<M>) const {
     return FixedInt<N | M>();
   }
 
   template <int M>
-  EIGEN_CONSTEXPR FixedInt<N & M> operator&(FixedInt<M>) const {
+  constexpr FixedInt<N & M> operator&(FixedInt<M>) const {
     return FixedInt<N & M>();
   }
 
   // Needed in C++14 to allow fix<N>():
-  EIGEN_CONSTEXPR FixedInt operator()() const { return *this; }
+  constexpr FixedInt operator()() const { return *this; }
 
-  VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
+  constexpr VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); }
 };
 
 /** \internal
diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h
index 136942c..befb485 100644
--- a/Eigen/src/Core/util/SymbolicIndex.h
+++ b/Eigen/src/Core/util/SymbolicIndex.h
@@ -44,6 +44,8 @@
 
 template <typename Tag>
 class Symbol;
+template <typename Tag, typename Type>
+class SymbolValue;
 template <typename Arg0>
 class NegateExpr;
 template <typename Arg1, typename Arg2>
@@ -52,136 +54,123 @@
 class ProductExpr;
 template <typename Arg1, typename Arg2>
 class QuotientExpr;
-
-// A simple wrapper around an integral value to provide the eval method.
-// We could also use a free-function symbolic_eval...
 template <typename IndexType = Index>
-class ValueExpr {
- public:
-  ValueExpr(IndexType val) : m_value(val) {}
-  template <typename T>
-  IndexType eval_impl(const T&) const {
-    return m_value;
-  }
-
- protected:
-  IndexType m_value;
-};
-
-// Specialization for compile-time value,
-// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
-template <int N>
-class ValueExpr<internal::FixedInt<N> > {
- public:
-  ValueExpr() {}
-  template <typename T>
-  EIGEN_CONSTEXPR Index eval_impl(const T&) const {
-    return N;
-  }
-};
+class ValueExpr;
 
 /** \class BaseExpr
  * \ingroup Core_Module
  * Common base class of any symbolic expressions
  */
-template <typename Derived>
+template <typename Derived_>
 class BaseExpr {
  public:
-  const Derived& derived() const { return *static_cast<const Derived*>(this); }
+  using Derived = Derived_;
+  constexpr const Derived& derived() const { return *static_cast<const Derived*>(this); }
 
   /** Evaluate the expression given the \a values of the symbols.
    *
-   * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue
-   *               as constructed by SymbolExpr::operator= operator.
+   * \param values defines the values of the symbols, as constructed by SymbolExpr::operator= operator.
    *
    */
-  template <typename T>
-  Index eval(const T& values) const {
-    return derived().eval_impl(values);
+  template <typename... Tags, typename... Types>
+  constexpr Index eval(const SymbolValue<Tags, Types>&... values) const {
+    return derived().eval_impl(values...);
   }
 
-  template <typename... Types>
-  Index eval(Types&&... values) const {
-    return derived().eval_impl(std::make_tuple(values...));
+  /** Evaluate the expression at compile time given the \a values of the symbols.
+   *
+   * If a value is not known at compile-time, returns Eigen::Undefined.
+   *
+   */
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time(const SymbolValue<Tags, Types>&...) {
+    return Derived::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
   }
 
-  NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
+  constexpr NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); }
 
-  AddExpr<Derived, ValueExpr<> > operator+(Index b) const { return AddExpr<Derived, ValueExpr<> >(derived(), b); }
-  AddExpr<Derived, ValueExpr<> > operator-(Index a) const { return AddExpr<Derived, ValueExpr<> >(derived(), -a); }
-  ProductExpr<Derived, ValueExpr<> > operator*(Index a) const {
+  constexpr AddExpr<Derived, ValueExpr<>> operator+(Index b) const {
+    return AddExpr<Derived, ValueExpr<>>(derived(), b);
+  }
+  constexpr AddExpr<Derived, ValueExpr<>> operator-(Index a) const {
+    return AddExpr<Derived, ValueExpr<>>(derived(), -a);
+  }
+  constexpr ProductExpr<Derived, ValueExpr<>> operator*(Index a) const {
     return ProductExpr<Derived, ValueExpr<> >(derived(), a);
   }
-  QuotientExpr<Derived, ValueExpr<> > operator/(Index a) const {
+  constexpr QuotientExpr<Derived, ValueExpr<>> operator/(Index a) const {
     return QuotientExpr<Derived, ValueExpr<> >(derived(), a);
   }
 
-  friend AddExpr<Derived, ValueExpr<> > operator+(Index a, const BaseExpr& b) {
+  friend constexpr AddExpr<Derived, ValueExpr<>> operator+(Index a, const BaseExpr& b) {
     return AddExpr<Derived, ValueExpr<> >(b.derived(), a);
   }
-  friend AddExpr<NegateExpr<Derived>, ValueExpr<> > operator-(Index a, const BaseExpr& b) {
+  friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<>> operator-(Index a, const BaseExpr& b) {
     return AddExpr<NegateExpr<Derived>, ValueExpr<> >(-b.derived(), a);
   }
-  friend ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
+  friend constexpr ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) {
     return ProductExpr<ValueExpr<>, Derived>(a, b.derived());
   }
-  friend QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
+  friend constexpr QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) {
     return QuotientExpr<ValueExpr<>, Derived>(a, b.derived());
   }
 
   template <int N>
-  AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>) const {
+  constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>) const {
     return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
   }
   template <int N>
-  AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N>) const {
+  constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<-N>>> operator-(internal::FixedInt<N>) const {
     return AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >());
   }
   template <int N>
-  ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N>) const {
+  constexpr ProductExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator*(internal::FixedInt<N>) const {
     return ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
   }
   template <int N>
-  QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N>) const {
+  constexpr QuotientExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator/(internal::FixedInt<N>) const {
     return QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >());
   }
 
   template <int N>
-  friend AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>, const BaseExpr& b) {
+  friend constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>,
+                                                                                const BaseExpr& b) {
     return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >());
   }
   template <int N>
-  friend AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N>,
-                                                                                    const BaseExpr& b) {
+  friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N>>> operator-(internal::FixedInt<N>,
+                                                                                            const BaseExpr& b) {
     return AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > >(-b.derived(),
                                                                             ValueExpr<internal::FixedInt<N> >());
   }
   template <int N>
-  friend ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator*(internal::FixedInt<N>, const BaseExpr& b) {
+  friend constexpr ProductExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator*(internal::FixedInt<N>,
+                                                                                    const BaseExpr& b) {
     return ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
   }
   template <int N>
-  friend QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator/(internal::FixedInt<N>, const BaseExpr& b) {
+  friend constexpr QuotientExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator/(internal::FixedInt<N>,
+                                                                                     const BaseExpr& b) {
     return QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived());
   }
 
   template <typename OtherDerived>
-  AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
+  constexpr AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const {
     return AddExpr<Derived, OtherDerived>(derived(), b.derived());
   }
 
   template <typename OtherDerived>
-  AddExpr<Derived, NegateExpr<OtherDerived> > operator-(const BaseExpr<OtherDerived>& b) const {
+  constexpr AddExpr<Derived, NegateExpr<OtherDerived>> operator-(const BaseExpr<OtherDerived>& b) const {
     return AddExpr<Derived, NegateExpr<OtherDerived> >(derived(), -b.derived());
   }
 
   template <typename OtherDerived>
-  ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
+  constexpr ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const {
     return ProductExpr<Derived, OtherDerived>(derived(), b.derived());
   }
 
   template <typename OtherDerived>
-  QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
+  constexpr QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const {
     return QuotientExpr<Derived, OtherDerived>(derived(), b.derived());
   }
 };
@@ -193,21 +182,137 @@
   enum { value = internal::is_convertible<T, BaseExpr<T> >::value };
 };
 
+// A simple wrapper around an integral value to provide the eval method.
+// We could also use a free-function symbolic_eval...
+template <typename IndexType>
+class ValueExpr : BaseExpr<ValueExpr<IndexType>> {
+ public:
+  constexpr ValueExpr() = default;
+  constexpr ValueExpr(IndexType val) : value_(val) {}
+  template <typename... Tags, typename... Types>
+  constexpr IndexType eval_impl(const SymbolValue<Tags, Types>&...) const {
+    return value_;
+  }
+  template <typename... Tags, typename... Types>
+  static constexpr IndexType eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    return IndexType(Undefined);
+  }
+
+ protected:
+  IndexType value_;
+};
+
+// Specialization for compile-time value,
+// It is similar to ValueExpr(N) but this version helps the compiler to generate better code.
+template <int N>
+class ValueExpr<internal::FixedInt<N>> : public BaseExpr<ValueExpr<internal::FixedInt<N>>> {
+ public:
+  constexpr ValueExpr() = default;
+  constexpr ValueExpr(internal::FixedInt<N>) {}
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
+    return Index(N);
+  }
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    return Index(N);
+  }
+};
+
 /** Represents the actual value of a symbol identified by its tag
  *
  * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used.
  */
+template <typename Tag, typename Type>
+class SymbolValue : public BaseExpr<SymbolValue<Tag, Type>> {};
+
 template <typename Tag>
-class SymbolValue {
+class SymbolValue<Tag, Index> : public BaseExpr<SymbolValue<Tag, Index>> {
  public:
+  constexpr SymbolValue() = default;
+
   /** Default constructor from the value \a val */
-  SymbolValue(Index val) : m_value(val) {}
+  constexpr SymbolValue(Index val) : value_(val) {}
 
   /** \returns the stored value of the symbol */
-  Index value() const { return m_value; }
+  constexpr Index value() const { return value_; }
+
+  /** \returns the stored value of the symbol at compile time, or Undefined if not known. */
+  static constexpr Index value_at_compile_time() { return Index(Undefined); }
+
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
+    return value();
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    return value_at_compile_time();
+  }
 
  protected:
-  Index m_value;
+  Index value_;
+};
+
+template <typename Tag, int N>
+class SymbolValue<Tag, internal::FixedInt<N>> : public BaseExpr<SymbolValue<Tag, internal::FixedInt<N>>> {
+ public:
+  constexpr SymbolValue() = default;
+
+  /** Default constructor from the value \a val */
+  constexpr SymbolValue(internal::FixedInt<N>){};
+
+  /** \returns the stored value of the symbol */
+  constexpr Index value() const { return static_cast<Index>(N); }
+
+  /** \returns the stored value of the symbol at compile time, or Undefined if not known. */
+  static constexpr Index value_at_compile_time() { return static_cast<Index>(N); }
+
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const {
+    return value();
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    return value_at_compile_time();
+  }
+};
+
+// Find and return a symbol value based on the tag.
+template <typename Tag, typename... Types>
+struct EvalSymbolValueHelper;
+
+// Empty base case, symbol not found.
+template <typename Tag>
+struct EvalSymbolValueHelper<Tag> {
+  static constexpr Index eval_impl() {
+    eigen_assert(false && "Symbol not found.");
+    return Index(Undefined);
+  }
+  static constexpr Index eval_at_compile_time_impl() { return Index(Undefined); }
+};
+
+// We found a symbol value matching the provided Tag!
+template <typename Tag, typename Type, typename... OtherTypes>
+struct EvalSymbolValueHelper<Tag, SymbolValue<Tag, Type>, OtherTypes...> {
+  static constexpr Index eval_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
+    return symbol.value();
+  }
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) {
+    return symbol.value_at_compile_time();
+  }
+};
+
+// No symbol value in first value, recursive search starting with next.
+template <typename Tag, typename T1, typename... OtherTypes>
+struct EvalSymbolValueHelper<Tag, T1, OtherTypes...> {
+  static constexpr Index eval_impl(const T1&, const OtherTypes&... values) {
+    return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_impl(values...);
+  }
+  static constexpr Index eval_at_compile_time_impl(const T1&, const OtherTypes&...) {
+    return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_at_compile_time_impl(OtherTypes{}...);
+  }
 };
 
 /** Expression of a symbol uniquely identified by the template parameter type \c tag */
@@ -217,32 +322,47 @@
   /** Alias to the template parameter \c tag */
   typedef tag Tag;
 
-  SymbolExpr() {}
+  constexpr SymbolExpr() = default;
 
   /** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag.
    *
    * The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified
    * runtime-time value.
    */
-  SymbolValue<Tag> operator=(Index val) const { return SymbolValue<Tag>(val); }
+  constexpr SymbolValue<Tag, Index> operator=(Index val) const { return SymbolValue<Tag, Index>(val); }
 
-  Index eval_impl(const SymbolValue<Tag>& values) const { return values.value(); }
+  template <int N>
+  constexpr SymbolValue<Tag, internal::FixedInt<N>> operator=(internal::FixedInt<N>) const {
+    return SymbolValue<Tag, internal::FixedInt<N>>{internal::FixedInt<N>{}};
+  }
 
-  // C++14 versions suitable for multiple symbols
-  template <typename... Types>
-  Index eval_impl(const std::tuple<Types...>& values) const {
-    return std::get<SymbolValue<Tag> >(values).value();
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
+    return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_impl(values...);
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_at_compile_time_impl(
+        SymbolValue<Tags, Types>{}...);
   }
 };
 
 template <typename Arg0>
 class NegateExpr : public BaseExpr<NegateExpr<Arg0> > {
  public:
-  NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
+  constexpr NegateExpr() = default;
+  constexpr NegateExpr(const Arg0& arg0) : m_arg0(arg0) {}
 
-  template <typename T>
-  Index eval_impl(const T& values) const {
-    return -m_arg0.eval_impl(values);
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
+    return -m_arg0.eval_impl(values...);
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    constexpr Index v = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    return (v == Undefined) ? Undefined : -v;
   }
 
  protected:
@@ -252,11 +372,19 @@
 template <typename Arg0, typename Arg1>
 class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > {
  public:
-  AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
+  constexpr AddExpr() = default;
+  constexpr AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
 
-  template <typename T>
-  Index eval_impl(const T& values) const {
-    return m_arg0.eval_impl(values) + m_arg1.eval_impl(values);
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
+    return m_arg0.eval_impl(values...) + m_arg1.eval_impl(values...);
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 + v1;
   }
 
  protected:
@@ -267,11 +395,19 @@
 template <typename Arg0, typename Arg1>
 class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > {
  public:
-  ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
+  constexpr ProductExpr() = default;
+  constexpr ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
 
-  template <typename T>
-  Index eval_impl(const T& values) const {
-    return m_arg0.eval_impl(values) * m_arg1.eval_impl(values);
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
+    return m_arg0.eval_impl(values...) * m_arg1.eval_impl(values...);
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 * v1;
   }
 
  protected:
@@ -282,11 +418,19 @@
 template <typename Arg0, typename Arg1>
 class QuotientExpr : public BaseExpr<QuotientExpr<Arg0, Arg1> > {
  public:
-  QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
+  constexpr QuotientExpr() = default;
+  constexpr QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {}
 
-  template <typename T>
-  Index eval_impl(const T& values) const {
-    return m_arg0.eval_impl(values) / m_arg1.eval_impl(values);
+  template <typename... Tags, typename... Types>
+  constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const {
+    return m_arg0.eval_impl(values...) / m_arg1.eval_impl(values...);
+  }
+
+  template <typename... Tags, typename... Types>
+  static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) {
+    constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...);
+    return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 / v1;
   }
 
  protected:
diff --git a/Eigen/src/plugins/IndexedViewMethods.inc b/Eigen/src/plugins/IndexedViewMethods.inc
index 26e7b5f..c3df429 100644
--- a/Eigen/src/plugins/IndexedViewMethods.inc
+++ b/Eigen/src/plugins/IndexedViewMethods.inc
@@ -9,51 +9,47 @@
 
 #if !defined(EIGEN_PARSED_BY_DOXYGEN)
 
-protected:
+public:
 // define some aliases to ease readability
 
 template <typename Indices>
-using IvcRowType = typename internal::IndexedViewCompatibleType<Indices, RowsAtCompileTime>::type;
+using IvcRowType = typename internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::type;
 
 template <typename Indices>
-using IvcColType = typename internal::IndexedViewCompatibleType<Indices, ColsAtCompileTime>::type;
+using IvcColType = typename internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::type;
 
 template <typename Indices>
-using IvcType = typename internal::IndexedViewCompatibleType<Indices, SizeAtCompileTime>::type;
-
-typedef typename internal::IndexedViewCompatibleType<Index, 1>::type IvcIndex;
+using IvcSizeType = typename internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::type;
 
 template <typename Indices>
 inline IvcRowType<Indices> ivcRow(const Indices& indices) const {
-  return internal::makeIndexedViewCompatible(
-      indices, internal::variable_if_dynamic<Index, RowsAtCompileTime>(derived().rows()), Specialized);
+  return internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::CreateIndexSequence(indices,
+                                                                                                    derived().rows());
 }
 
 template <typename Indices>
 inline IvcColType<Indices> ivcCol(const Indices& indices) const {
-  return internal::makeIndexedViewCompatible(
-      indices, internal::variable_if_dynamic<Index, ColsAtCompileTime>(derived().cols()), Specialized);
+  return internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::CreateIndexSequence(indices,
+                                                                                                    derived().cols());
 }
 
 template <typename Indices>
-inline IvcType<Indices> ivcSize(const Indices& indices) const {
-  return internal::makeIndexedViewCompatible(
-      indices, internal::variable_if_dynamic<Index, SizeAtCompileTime>(derived().size()), Specialized);
+inline IvcSizeType<Indices> ivcSize(const Indices& indices) const {
+  return internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::CreateIndexSequence(indices,
+                                                                                                    derived().size());
+  ;
 }
 
 // this helper class assumes internal::valid_indexed_view_overload<RowIndices, ColIndices>::value == true
-template <typename RowIndices, typename ColIndices,
-          bool UseSymbolic =
-              internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar,
-          bool UseBlock =
-              internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock,
-          bool UseGeneric = internal::traits<
-              IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView>
+template <typename RowIndices, typename ColIndices, typename EnableIf = void>
 struct IndexedViewSelector;
 
 // Generic
 template <typename RowIndices, typename ColIndices>
-struct IndexedViewSelector<RowIndices, ColIndices, false, false, true> {
+struct IndexedViewSelector<
+    RowIndices, ColIndices,
+    std::enable_if_t<
+        internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView>> {
   using ReturnType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
   using ConstReturnType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
 
@@ -68,60 +64,73 @@
 
 // Block
 template <typename RowIndices, typename ColIndices>
-struct IndexedViewSelector<RowIndices, ColIndices, false, true, false> {
-  using IndexedViewType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
-  using ConstIndexedViewType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>;
+struct IndexedViewSelector<RowIndices, ColIndices,
+                           std::enable_if_t<internal::traits<
+                               IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock>> {
+  using ActualRowIndices = IvcRowType<RowIndices>;
+  using ActualColIndices = IvcColType<ColIndices>;
+  using IndexedViewType = IndexedView<Derived, ActualRowIndices, ActualColIndices>;
+  using ConstIndexedViewType = IndexedView<const Derived, ActualRowIndices, ActualColIndices>;
   using ReturnType = typename internal::traits<IndexedViewType>::BlockType;
   using ConstReturnType = typename internal::traits<ConstIndexedViewType>::BlockType;
+  using RowHelper = internal::IndexedViewHelper<ActualRowIndices>;
+  using ColHelper = internal::IndexedViewHelper<ActualColIndices>;
 
   static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) {
-    IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices);
-    IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices);
-    return ReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices),
-                      internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices));
+    auto actualRowIndices = derived.ivcRow(rowIndices);
+    auto actualColIndices = derived.ivcCol(colIndices);
+    return ReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices),
+                      RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices));
   }
   static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices,
                                     const ColIndices& colIndices) {
-    IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices);
-    IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices);
-    return ConstReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices),
-                           internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices));
+    auto actualRowIndices = derived.ivcRow(rowIndices);
+    auto actualColIndices = derived.ivcCol(colIndices);
+    return ConstReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices),
+                           RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices));
   }
 };
 
-// Symbolic
+// Scalar
 template <typename RowIndices, typename ColIndices>
-struct IndexedViewSelector<RowIndices, ColIndices, true, false, false> {
+struct IndexedViewSelector<RowIndices, ColIndices,
+                           std::enable_if_t<internal::traits<
+                               IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar>> {
   using ReturnType = typename DenseBase<Derived>::Scalar&;
   using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType;
-
+  using ActualRowIndices = IvcRowType<RowIndices>;
+  using ActualColIndices = IvcColType<ColIndices>;
+  using RowHelper = internal::IndexedViewHelper<ActualRowIndices>;
+  using ColHelper = internal::IndexedViewHelper<ActualColIndices>;
   static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) {
-    return derived(internal::eval_expr_given_size(rowIndices, derived.rows()),
-                   internal::eval_expr_given_size(colIndices, derived.cols()));
+    auto actualRowIndices = derived.ivcRow(rowIndices);
+    auto actualColIndices = derived.ivcCol(colIndices);
+    return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices));
   }
   static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices,
                                     const ColIndices& colIndices) {
-    return derived(internal::eval_expr_given_size(rowIndices, derived.rows()),
-                   internal::eval_expr_given_size(colIndices, derived.cols()));
+    auto actualRowIndices = derived.ivcRow(rowIndices);
+    auto actualColIndices = derived.ivcCol(colIndices);
+    return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices));
   }
 };
 
 // this helper class assumes internal::is_valid_index_type<Indices>::value == false
-template <typename Indices, bool UseSymbolic = symbolic::is_symbolic<Indices>::value,
-          bool UseBlock = !UseSymbolic && internal::get_compile_time_incr<IvcType<Indices>>::value == 1,
-          bool UseGeneric = !UseSymbolic && !UseBlock>
+template <typename Indices, typename EnableIf = void>
 struct VectorIndexedViewSelector;
 
 // Generic
 template <typename Indices>
-struct VectorIndexedViewSelector<Indices, false, false, true> {
+struct VectorIndexedViewSelector<
+    Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value &&
+                              internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime != 1>> {
   static constexpr bool IsRowMajor = DenseBase<Derived>::IsRowMajor;
+  using ZeroIndex = internal::SingleRange<Index(0)>;
+  using RowMajorReturnType = IndexedView<Derived, ZeroIndex, IvcSizeType<Indices>>;
+  using ConstRowMajorReturnType = IndexedView<const Derived, ZeroIndex, IvcSizeType<Indices>>;
 
-  using RowMajorReturnType = IndexedView<Derived, IvcIndex, IvcType<Indices>>;
-  using ConstRowMajorReturnType = IndexedView<const Derived, IvcIndex, IvcType<Indices>>;
-
-  using ColMajorReturnType = IndexedView<Derived, IvcType<Indices>, IvcIndex>;
-  using ConstColMajorReturnType = IndexedView<const Derived, IvcType<Indices>, IvcIndex>;
+  using ColMajorReturnType = IndexedView<Derived, IvcSizeType<Indices>, ZeroIndex>;
+  using ConstColMajorReturnType = IndexedView<const Derived, IvcSizeType<Indices>, ZeroIndex>;
 
   using ReturnType = typename internal::conditional<IsRowMajor, RowMajorReturnType, ColMajorReturnType>::type;
   using ConstReturnType =
@@ -129,49 +138,53 @@
 
   template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true>
   static inline RowMajorReturnType run(Derived& derived, const Indices& indices) {
-    return RowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices));
+    return RowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices));
   }
   template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true>
   static inline ConstRowMajorReturnType run(const Derived& derived, const Indices& indices) {
-    return ConstRowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices));
+    return ConstRowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices));
   }
   template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true>
   static inline ColMajorReturnType run(Derived& derived, const Indices& indices) {
-    return ColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0));
+    return ColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0));
   }
   template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true>
   static inline ConstColMajorReturnType run(const Derived& derived, const Indices& indices) {
-    return ConstColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0));
+    return ConstColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0));
   }
 };
 
 // Block
 template <typename Indices>
-struct VectorIndexedViewSelector<Indices, false, true, false> {
-  using ReturnType = VectorBlock<Derived, internal::array_size<Indices>::value>;
-  using ConstReturnType = VectorBlock<const Derived, internal::array_size<Indices>::value>;
-
+struct VectorIndexedViewSelector<
+    Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value &&
+                              internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime == 1>> {
+  using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>;
+  using ReturnType = VectorBlock<Derived, Helper::SizeAtCompileTime>;
+  using ConstReturnType = VectorBlock<const Derived, Helper::SizeAtCompileTime>;
   static inline ReturnType run(Derived& derived, const Indices& indices) {
-    IvcType<Indices> actualIndices = derived.ivcSize(indices);
-    return ReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices));
+    auto actualIndices = derived.ivcSize(indices);
+    return ReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices));
   }
   static inline ConstReturnType run(const Derived& derived, const Indices& indices) {
-    IvcType<Indices> actualIndices = derived.ivcSize(indices);
-    return ConstReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices));
+    auto actualIndices = derived.ivcSize(indices);
+    return ConstReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices));
   }
 };
 
 // Symbolic
 template <typename Indices>
-struct VectorIndexedViewSelector<Indices, true, false, false> {
+struct VectorIndexedViewSelector<Indices, std::enable_if_t<internal::is_single_range<IvcSizeType<Indices>>::value>> {
   using ReturnType = typename DenseBase<Derived>::Scalar&;
   using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType;
-
-  static inline ReturnType run(Derived& derived, const Indices& id) {
-    return derived(internal::eval_expr_given_size(id, derived.size()));
+  using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>;
+  static inline ReturnType run(Derived& derived, const Indices& indices) {
+    auto actualIndices = derived.ivcSize(indices);
+    return derived(Helper::first(actualIndices));
   }
-  static inline ConstReturnType run(const Derived& derived, const Indices& id) {
-    return derived(internal::eval_expr_given_size(id, derived.size()));
+  static inline ConstReturnType run(const Derived& derived, const Indices& indices) {
+    auto actualIndices = derived.ivcSize(indices);
+    return derived(Helper::first(actualIndices));
   }
 };
 
diff --git a/doc/TutorialSlicingIndexing.dox b/doc/TutorialSlicingIndexing.dox
index 7f89554..6ebaa2d 100644
--- a/doc/TutorialSlicingIndexing.dox
+++ b/doc/TutorialSlicingIndexing.dox
@@ -86,12 +86,12 @@
   <td></td>
 </tr>
 <tr>
-  <td>First \c n odd rows A</td>
+  <td>First \c n odd rows of A</td>
   <td>\code A(seqN(1,n,2), all) \endcode</td>
   <td></td>
 </tr>
 <tr>
-  <td>The last past one column</td>
+  <td>The second-last column</td>
   <td>\code A(all, last-1) \endcode</td>
   <td>\code A.col(A.cols()-2) \endcode</td>
 </tr>
@@ -158,7 +158,7 @@
 \endcode
 
 We can revisit the <i>even columns of A</i> example as follows:
-\code A(all, seq(0,last,fix<2>))
+\code A(all, seq(fix<0>,last,fix<2>))
 \endcode
 
 
diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp
index d3cf4a6..f165e8b 100644
--- a/test/indexed_view.cpp
+++ b/test/indexed_view.cpp
@@ -527,10 +527,323 @@
   }
 }
 
+void check_tutorial_examples() {
+  constexpr int kRows = 11;
+  constexpr int kCols = 21;
+  Matrix<double, kRows, kCols> A = Matrix<double, kRows, kCols>::Random();
+  Vector<double, kRows> v = Vector<double, kRows>::Random();
+
+  {
+    auto slice = A(seqN(fix<0>, fix<5>, fix<2>), seqN(fix<2>, fix<7>, fix<1>));
+    EIGEN_UNUSED_VARIABLE(slice);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), 7);
+  }
+  {
+    auto slice = A(seqN(fix<0>, fix<5>, fix<2>), indexing::all);
+    EIGEN_UNUSED_VARIABLE(slice);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5);
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), kCols);
+  }
+
+  // Examples from slicing tutorial.
+  // Bottom-left corner.
+  {
+    Index i = 3;
+    Index n = 5;
+    auto slice = A(seq(i, indexing::last), seqN(0, n));
+    auto block = A.bottomLeftCorner(A.rows() - i, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), Dynamic);
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), Dynamic);
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto i = fix<3>;
+    auto n = fix<5>;
+    auto slice = A(seq(i, indexing::last), seqN(fix<0>, n));
+    auto block = A.bottomLeftCorner(fix<kRows> - i, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), A.RowsAtCompileTime - i);
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), n);
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Block starting at i,j of size m,n.
+  {
+    Index i = 4;
+    Index j = 2;
+    Index m = 3;
+    Index n = 5;
+    auto slice = A(seqN(i, m), seqN(j, n));
+    auto block = A.block(i, j, m, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto i = fix<4>;
+    auto j = fix<2>;
+    auto m = fix<3>;
+    auto n = fix<5>;
+    auto slice = A(seqN(i, m), seqN(j, n));
+    auto block = A.block(i, j, m, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Block starting at i0,j0 and ending at i1,j1.
+  {
+    Index i0 = 4;
+    Index i1 = 7;
+    Index j0 = 3;
+    Index j1 = 5;
+    auto slice = A(seq(i0, i1), seq(j0, j1));
+    auto block = A.block(i0, j0, i1 - i0 + 1, j1 - j0 + 1);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto i0 = fix<4>;
+    auto i1 = fix<7>;
+    auto j0 = fix<3>;
+    auto j1 = fix<5>;
+    auto slice = A(seq(i0, i1), seq(j0, j1));
+    auto block = A.block(i0, j0, i1 - i0 + fix<1>, j1 - j0 + fix<1>);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Even columns of A.
+  {
+    auto slice = A(all, seq(0, last, 2));
+    auto block =
+        Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<2 * kRows>>(A.data(), kRows, (kCols + 1) / 2);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto slice = A(all, seq(fix<0>, last, fix<2>));
+    auto block = Eigen::Map<Eigen::Matrix<double, kRows, (kCols + 1) / 2>, 0, OuterStride<2 * kRows>>(A.data());
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // First n odd rows of A.
+  {
+    Index n = 3;
+    auto slice = A(seqN(1, n, 2), all);
+    auto block = Eigen::Map<Eigen::Matrix<double, Dynamic, kCols>, 0, Stride<kRows, 2>>(A.data() + 1, n, kCols);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto n = fix<3>;
+    auto slice = A(seqN(fix<1>, n, fix<2>), all);
+    auto block = Eigen::Map<Eigen::Matrix<double, 3, kCols>, 0, Stride<kRows, 2>>(A.data() + 1);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // The second-last column.
+  {
+    auto slice = A(all, last - 1);
+    auto block = A.col(A.cols() - 2);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto slice = A(all, last - fix<1>);
+    auto block = A.col(fix<kCols> - fix<2>);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // The middle row.
+  {
+    auto slice = A(last / 2, all);
+    auto block = A.row((A.rows() - 1) / 2);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto slice = A(last / fix<2>, all);
+    auto block = A.row(fix<(kRows - 1) / 2>);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Last elements of v starting at i.
+  {
+    Index i = 7;
+    auto slice = v(seq(i, last));
+    auto block = v.tail(v.size() - i);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto i = fix<7>;
+    auto slice = v(seq(i, last));
+    auto block = v.tail(fix<kRows> - i);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Last n elements of v.
+  {
+    Index n = 6;
+    auto slice = v(seq(last + 1 - n, last));
+    auto block = v.tail(n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto n = fix<6>;
+    auto slice = v(seq(last + fix<1> - n, last));
+    auto block = v.tail(n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Last n elements of v.
+  {
+    Index n = 6;
+    auto slice = v(lastN(n));
+    auto block = v.tail(n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto n = fix<6>;
+    auto slice = v(lastN(n));
+    auto block = v.tail(n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Bottom-right corner of A of size m times n.
+  {
+    Index m = 3;
+    Index n = 6;
+    auto slice = A(lastN(m), lastN(n));
+    auto block = A.bottomRightCorner(m, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    auto m = fix<3>;
+    auto n = fix<6>;
+    auto slice = A(lastN(m), lastN(n));
+    auto block = A.bottomRightCorner(m, n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Last n columns with a stride of 3.
+  {
+    Index n = 4;
+    constexpr Index stride = 3;
+    auto slice = A(all, lastN(n, stride));
+    auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<stride * kRows>>(
+        A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    constexpr auto n = fix<4>;
+    constexpr auto stride = fix<3>;
+    auto slice = A(all, lastN(n, stride));
+    auto block = Eigen::Map<Eigen::Matrix<double, kRows, n>, 0, OuterStride<stride * kRows>>(
+        A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n);
+    VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime));
+    VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime));
+    VERIFY_IS_EQUAL(slice, block);
+  }
+
+  // Compile time size and increment.
+  {
+    auto slice1 = v(seq(last - fix<7>, last - fix<2>));
+    auto slice2 = v(seqN(last - 7, fix<6>));
+    VERIFY_IS_EQUAL(slice1, slice2);
+    VERIFY_IS_EQUAL(int(slice1.SizeAtCompileTime), 6);
+    VERIFY_IS_EQUAL(int(slice2.SizeAtCompileTime), 6);
+    auto slice3 = A(all, seq(fix<0>, last, fix<2>));
+    VERIFY_IS_EQUAL(int(slice3.RowsAtCompileTime), kRows);
+    VERIFY_IS_EQUAL(int(slice3.ColsAtCompileTime), (kCols + 1) / 2);
+  }
+
+  // Reverse order.
+  {
+    auto slice = A(all, seq(20, 10, fix<-2>));
+    auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<-2 * kRows>>(
+        A.data() + 20 * kRows, A.rows(), (20 - 10 + 2) / 2);
+    VERIFY_IS_EQUAL(slice, block);
+  }
+  {
+    Index n = 10;
+    auto slice1 = A(seqN(last, n, fix<-1>), all);
+    auto slice2 = A(lastN(n).reverse(), all);
+    VERIFY_IS_EQUAL(slice1, slice2);
+  }
+
+  // Array of indices.
+  {
+    std::vector<int> ind{4, 2, 5, 5, 3};
+    auto slice1 = A(all, ind);
+    for (int i = 0; i < ind.size(); ++i) {
+      VERIFY_IS_EQUAL(slice1.col(i), A.col(ind[i]));
+    }
+
+    auto slice2 = A(all, {4, 2, 5, 5, 3});
+    VERIFY_IS_EQUAL(slice1, slice2);
+
+    Eigen::ArrayXi indarray(5);
+    indarray << 4, 2, 5, 5, 3;
+    auto slice3 = A(all, indarray);
+    VERIFY_IS_EQUAL(slice1, slice3);
+  }
+
+  // Custom index list.
+  {
+    struct pad {
+      Index size() const { return out_size; }
+      Index operator[](Index i) const { return std::max<Index>(0, i - (out_size - in_size)); }
+      Index in_size, out_size;
+    };
+
+    auto slice = A(pad{3, 5}, pad{3, 5});
+    Eigen::MatrixXd B = slice;
+    VERIFY_IS_EQUAL(B.block(2, 2, 3, 3), A.block(0, 0, 3, 3));
+  }
+}
+
 EIGEN_DECLARE_TEST(indexed_view) {
   for (int i = 0; i < g_repeat; i++) {
     CALL_SUBTEST_1(check_indexed_view());
   }
+  CALL_SUBTEST_1(check_tutorial_examples());
 
   // static checks of some internals:
   STATIC_CHECK((internal::is_valid_index_type<int>::value));