diff --git a/core/src/main/scala/shapeless/alacarte.scala b/core/src/main/scala/shapeless/alacarte.scala index 960aa5384..167e4a5aa 100644 --- a/core/src/main/scala/shapeless/alacarte.scala +++ b/core/src/main/scala/shapeless/alacarte.scala @@ -88,9 +88,9 @@ trait PolymorphicEqualityFacet extends ProductISOFacet { def equals(c: C, other: Any): Boolean = (c.asInstanceOf[AnyRef] eq other.asInstanceOf[AnyRef]) || - typ.cast(other).map { that => + typ.cast(other).exists { that => (toProduct(c) == toProduct(that)) && canEqual(that, c) - }.getOrElse(false) + } def hashCode(c: C): Int = toProduct(c).hashCode } diff --git a/core/src/main/scala/shapeless/annotation.scala b/core/src/main/scala/shapeless/annotation.scala index 7dbdd4347..8b3e0bcb8 100644 --- a/core/src/main/scala/shapeless/annotation.scala +++ b/core/src/main/scala/shapeless/annotation.scala @@ -30,7 +30,7 @@ import scala.reflect.macros.whitebox * case class First(i: Int) * * @First(3) trait Something - * + * * * val somethingFirst = Annotation[First, Something].apply() * assert(somethingFirst == First(3)) @@ -179,7 +179,11 @@ class AnnotationMacros(val c: whitebox.Context) extends CaseClassMacros { def someTpe: Type = typeOf[Some[_]].typeConstructor def noneTpe: Type = typeOf[None.type] - // FIXME Most of the content of this method is cut-n-pasted from generic.scala + /** + * FIXME Most of the content of this method is cut-n-pasted from generic.scala + * + * @return The AST of the `tpe` constructor. + */ def construct(tpe: Type): List[Tree] => Tree = { // FIXME Cut-n-pasted from generic.scala val sym = tpe.typeSymbol diff --git a/core/src/main/scala/shapeless/generic.scala b/core/src/main/scala/shapeless/generic.scala index d8d5d9e48..499c88065 100644 --- a/core/src/main/scala/shapeless/generic.scala +++ b/core/src/main/scala/shapeless/generic.scala @@ -283,15 +283,19 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { def isReprType(tpe: Type): Boolean = tpe <:< hlistTpe || tpe <:< coproductTpe - def isReprType1(tpe: Type): Boolean = { - val normalized = appliedType(tpe, WildcardType).dealias - normalized <:< hlistTpe || normalized <:< coproductTpe - } + def isReprType1(tpe: Type): Boolean = + isReprType(lowerKind(tpe)) + /** + * Lower the order of `tpe`'s kind by applying `Any` in place of all type parameters (`Any` is poly-kinded). + * Note that the resulting type is dealiased before being returned. + * + * {{{ + * lowerKind(typeOf[List[_]].typeConstructor) -> List[Any] + * }}} + */ def lowerKind(tpe: Type): Type = - if(tpe.takesTypeArgs) - appliedType(tpe, List(typeOf[Any])).dealias - else tpe + appliedType(tpe, tpe.typeParams.map(_ => definitions.AnyTpe)).dealias def isProductAux(tpe: Type): Boolean = tpe.typeSymbol.isClass && { @@ -300,19 +304,16 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { } def isProduct(tpe: Type): Boolean = - tpe =:= typeOf[Unit] || (!(tpe =:= typeOf[AnyRef]) && isProductAux(tpe)) + tpe =:= definitions.UnitTpe || (!(tpe =:= definitions.AnyRefTpe) && isProductAux(tpe)) def isProduct1(tpe: Type): Boolean = - lowerKind(tpe) =:= typeOf[Unit] || (!(lowerKind(tpe) =:= typeOf[AnyRef]) && isProductAux(tpe)) + isProduct(lowerKind(tpe)) - def isCoproduct(tpe: Type): Boolean = { - val sym = tpe.typeSymbol - if(!sym.isClass) false - else { - val sym = classSym(tpe) - (sym.isTrait || sym.isAbstract) && sym.isSealed + def isCoproduct(tpe: Type): Boolean = + tpe.typeSymbol.isClass && { + val cls = classSym(tpe) + (cls.isTrait || cls.isAbstract) && cls.isSealed } - } def ownerChain(sym: Symbol): List[Symbol] = { @tailrec @@ -328,6 +329,10 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { nameStr.contains("$anon") || nameStr == "" } + /** + * @return a List of name and type pairs for the fields of type `tpe`. + * @see [[isCaseAccessorLike]] for the definition of what is considered a field. + * */ def fieldsOf(tpe: Type): List[(TermName, Type)] = { val clazz = tpe.typeSymbol.asClass val isCaseClass = clazz.isCaseClass @@ -473,14 +478,27 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { case (elem, acc) => q"_root_.shapeless.::($elem, $acc)" } + /** + * Fold `items` into a type using `cons` as a type constructor. + * + * {{{ + * mkCompoundTpe(hnilTpe, hconsTpe, Seq(typeOf[String], typeOf[Int])) -> String :: Int :: HNil + * }}} + */ def mkCompoundTpe(nil: Type, cons: Type, items: Seq[Type]): Type = items.foldRight(nil) { (tpe, acc) => appliedType(cons, List(devarargify(tpe), acc)) } + /** + * Convert `items` to corresponding HList type. + */ def mkHListTpe(items: Seq[Type]): Type = mkCompoundTpe(hnilTpe, hconsTpe, items) + /** + * Convert `items` to corresponding Coproduct type. + */ def mkCoproductTpe(items: Seq[Type]): Type = mkCompoundTpe(cnilTpe, cconsTpe, items) @@ -698,6 +716,9 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { mkAttributedRef(pre, getter) } + /** + * Check if `sym` or any of its overrides are annotated by [[nonGeneric]]. + */ def isNonGeneric(sym: Symbol): Boolean = { def check(sym: Symbol): Boolean = { // See https://issues.scala-lang.org/browse/SI-7424 @@ -719,9 +740,16 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { def isVararg(tpe: Type): Boolean = tpe.typeSymbol == c.universe.definitions.RepeatedParamClass + /** + * Convert a varargs type to corresponding Seq type. + * + * {{{ + * String* -> Seq[String] + * }}} + */ def devarargify(tpe: Type): Type = tpe match { - case TypeRef(pre, _, args) if isVararg(tpe) => + case TypeRef(_, _, args) if isVararg(tpe) => appliedType(varargTC, args) case _ => tpe } @@ -838,7 +866,7 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { narrow(tree, tpe) def mkCtorDtor0(elems0: List[(TermName, Type)]) = { - val elems = elems0.map { case (name, tpe) => (TermName(c.freshName("pat")), tpe) } + val elems = elems0.map { case (_, tpe) => (TermName(c.freshName("pat")), tpe) } val pattern = pq"${companionRef(tpe)}(..${elems.map { case (binder, tpe) => if(isVararg(tpe)) pq"$binder @ $repWCard" else pq"$binder"}})" val reprPattern = elems.foldRight(q"_root_.shapeless.HNil": Tree) { @@ -883,7 +911,7 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { c.internal.gen.mkAttributedRef(pre, sym.asModule) case TypeRef(pre, sym, List()) if sym.isModuleClass => c.internal.gen.mkAttributedRef(pre, sym.asClass.module) - case other => + case _ => abort(s"Bad case object-like type $tpe") } new CtorDtor {