diff --git a/build.sbt b/build.sbt index 50c64a1..599f2fd 100644 --- a/build.sbt +++ b/build.sbt @@ -19,6 +19,7 @@ fork := true libraryDependencies ++= List( scalaOrganization.value % "scala-compiler" % scalaVersion.value % "provided", "com.chuusai" %% "shapeless" % "2.3.3" % "test", + "dev.zio" %% "zio" % "1.0.4" % "test" ) libraryDependencies += "org.specs2" %% "specs2-core" % "4.5.1" % Test diff --git a/src/main/scala/splain/format/Formatters.scala b/src/main/scala/splain/format/Formatters.scala index 99801b7..b8a2605 100644 --- a/src/main/scala/splain/format/Formatters.scala +++ b/src/main/scala/splain/format/Formatters.scala @@ -169,6 +169,32 @@ trait Formatters { self: Analyzer => tpes.filterNot(t => ignoredTypes.exists(_ =:= t)) } + object DeepRefined { + def unapply(tpe: Type): Option[(List[Type], Scope)] = + tpe match { + case TypeRef(pre, sym, List(RefinedType(parents, decls))) + if decls.isEmpty && pre.typeSymbol.fullName == "zio" && sym.fullName == "zio.Has" => + val sanitized = sanitizeParents(parents) + if (sanitized.length == 1) { + Some((List(TypeRef(pre, sym, sanitized.headOption.toList)), decls)) + } else { + None + } + case Refined(types, scope) => + if (scope.isEmpty) { + val subtypes = types.map(_.dealias).flatMap { + case DeepRefined(types, _) => types + case tpe => List(tpe) + } + Some((subtypes, scope)) + } else { + Some((types, scope)) + } + case _ => + None + } + } + def formatDecl: Symbol => Formatted = { case DeclSymbol(n, t) => Decl(n, t) @@ -239,7 +265,7 @@ trait Formatters { self: Analyzer => def diff(left: Type, right: Type, top: Boolean): Option[Formatted] = (left, right) match { - case (Refined(leftParents, leftDecls), Refined(rightParents, rightDecls)) => + case (DeepRefined(leftParents, leftDecls), DeepRefined(rightParents, rightDecls)) => val parents = matchTypes(sanitizeParents(leftParents), sanitizeParents(rightParents)).sorted val decls = matchDecls(leftDecls.toList, rightDecls.toList).sorted Some(RefinedForm(parents, decls)) diff --git a/src/test/scala/splain/ErrorsSpec.scala b/src/test/scala/splain/ErrorsSpec.scala index d9bd39d..a35841d 100644 --- a/src/test/scala/splain/ErrorsSpec.scala +++ b/src/test/scala/splain/ErrorsSpec.scala @@ -115,6 +115,7 @@ class ErrorsSpec extends SpecBase { single types in function ${checkError("single-fn")} single types with free symbol ${checkError("single-free")} witness value types ${checkError("witness-value")} + zio test ${checkError("zlayer")} """ // def is = s2""" diff --git a/tests/zlayer/code.scala b/tests/zlayer/code.scala new file mode 100644 index 0000000..e86cf35 --- /dev/null +++ b/tests/zlayer/code.scala @@ -0,0 +1,20 @@ +import zio._ + +object layers { + + trait Service1 + trait Service2 + trait Service3 + trait Service4 + + val service1 = ZLayer.succeed(new Service1 {}) + + val service2 = ZLayer.succeed(new Service2 {}) + + val service3 = ZLayer.fromService { (_: Service1) => new Service3 {} } + + val service4 = ZLayer.succeed(new Service4 {}) + + val services: ULayer[Has[Service1] with Has[Service2] with Has[Service3] with Has[Service4]] = + service1 ++ service2 >+> service3// ++ service4 +} diff --git a/tests/zlayer/error b/tests/zlayer/error new file mode 100644 index 0000000..b40e0b2 --- /dev/null +++ b/tests/zlayer/error @@ -0,0 +1,2 @@ +type mismatch; + ZLayer[, Nothing, |Has[Service4] with Has[Service1] with Has[Service2] with Has[Service3]]