-
Couldn't load subscription status.
- Fork 1.4k
Add HasNoScope type class (#9597)
#9604
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
core/shared/src/main/scala-2/zio/HasNoScopeCompanionVersionSpecific.scala
Outdated
Show resolved
Hide resolved
core/shared/src/main/scala-2/zio/HasNoScopeCompanionVersionSpecific.scala
Outdated
Show resolved
Hide resolved
core/shared/src/main/scala-3/zio/HasNoScopeCompanionVersionSpecific.scala
Outdated
Show resolved
Hide resolved
managed-tests/shared/src/test/scala/zio/managed/HasNoScopeSpec.scala
Outdated
Show resolved
Hide resolved
82ee7e7 to
22b867b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is possible without a macro, but I couldn't get the Scope & case to work:
import zio.Scope
import zio.ZEnvironment
abstract class Foo
sealed abstract class HasNoScope[R]
object HasNoScope extends HighPriorityImplicits {
override protected val instance = new HasNoScope[Any] {}
def f[R: HasNoScope] = ???
f[Any] // compiles - correct
f[Foo & Any] // compiles - correct
//f[Scope] // doesn't compile - correct
f[Foo & Scope] // compiles - incorrect
sealed abstract class LowPriorityImplicits {
protected val instance: HasNoScope[Any]
@annotation.implicitAmbiguous("Cannot provde that ZEnvironment[${R}] does not contain zio.Scope")
implicit def supScope1[R >: Scope]: HasNoScope[R] =
instance.asInstanceOf[HasNoScope[R]]
implicit def supScope2[R >: Scope]: HasNoScope[R] =
instance.asInstanceOf[HasNoScope[R]]
}
sealed abstract class MediumPriorityImplicits extends LowPriorityImplicits {
implicit def hasNoScope[R]: HasNoScope[R] =
instance.asInstanceOf[HasNoScope[R]]
}
abstract class HighPriorityImplicits extends MediumPriorityImplicits {
implicit val hasNoScopeAny: HasNoScope[Any] = instance
}
| s"Can not prove that $rName does not contain a zio.Scope. Please add a context bound ${rName}: HasNoScope." | ||
| ) | ||
| } else { | ||
| '{ HasNoScope.noScope.asInstanceOf[HasNoScope[R]] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can cause some cyclic issues in edge cases. My suggestion would be to use protected def instance and the object can override with a val
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get the override val part
|
|
||
| import scala.quoted._ | ||
|
|
||
| private[zio] trait HasNoScopeCompanionVersionSpecific { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private[zio] trait HasNoScopeCompanionVersionSpecific { | |
| private[zio] abstract class HasNoScopeCompanionVersionSpecific { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
traits are compiled to interfaces which can introduce interface dispatch. In this case, it's probably equivalent. However, it's a good precedence to set going forward. It's not binary compat to go from class -> trait, but it's easy to go the other way (if necessary).
| import scala.language.experimental.macros | ||
| import scala.reflect.macros.blackbox | ||
|
|
||
| private[zio] trait HasNoScopeCompanionVersionSpecific { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| private[zio] trait HasNoScopeCompanionVersionSpecific { | |
| private[zio] abstract class HasNoScopeCompanionVersionSpecific { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
| sealed trait HasNoScope[R] | ||
|
|
||
| object HasNoScope extends HasNoScopeCompanionVersionSpecific { | ||
| val noScope: HasNoScope[Any] = new HasNoScope[Any] {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private/protected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am quite sure, that won't work. Because the access will be inlined and the place of inlining won't have the correct access rights
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you make it package-private it'll work. package-private methods don't exist on the JVM so they're compiled to public methods.
PS: It will also work if you make it private; but in that case the Scala compiler will create a public proxy method which we probably want to avoid
The macro works and is on the simple side of macros. I think it is okay. |
| @@ -0,0 +1,56 @@ | |||
| package zio.managed | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is the wrong place with this suite. Any reason it's not under the core-tests folder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just took a look where the other tests that use macros where. I can move it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes let's please move it. I'm not even sure why the other macro tests are under there but we should probably move those too (not in this PR ofc)
22b867b to
278295f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code LGTM, as discussed over Discord I think Scala 3's typecheck should be a transparent inline to correctly show the macro errors. That would allow unification of suites.
| sealed trait HasNoScope[R] | ||
|
|
||
| object HasNoScope extends HasNoScopeCompanionVersionSpecific { | ||
| override val instance: HasNoScope[Any] = new HasNoScope[Any] {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change this to package-private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be called by the inlined code of the macro. If it is not public, the compiler will fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package-private methods / vals are public when compiled. Have you tried changing it to package-private and it didn't work?
fixes #9597
/claim #9597