-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Support custom val symbol in ValDef.let #13936
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
8873ec9
to
afc5af3
Compare
If you already created the |
Maybe an example in the documentation of how to use |
Also, if you have the symbol of the |
Yes you can, but that's quite error prone. |
The quotes API will always be more error-prone than the quotes API. By using the symbol constructor we drove into an error-prone territory, the def lazyVal[T: Type, U: Type](rhs: Expr[T])(body: Expr[T] => Expr[U])(using Quotes): Expr[U] =
'{ lazy val x: T = $rhs; ${body('x)} }
def lazyVal[T: Type, U: Type](name: String, rhs: Expr[T])(body: Expr[T] => Expr[U])(using Quotes): Expr[U] =
// implement using reflection
// ...
// other variants of val definitions Then your example can be simplified to - val tpe = TypeRepr.of[String]
- val valSym = Symbol.newVal(
- Symbol.spliceOwner,
- "myValName",
- tpe,
- Flags.Lazy,
- Symbol.noSymbol
- )
- ValDef.let(Symbol.spliceOwner, valSym, Expr("foo").asTerm) { v =>
- '{ println(v) }.asTerm
- }
+ lazyVal("myValName", Expr("foo")) { x =>
+ '{ println(v) }
+ } I have always been against the addition of the The only place where once needs to use the |
?
Using the quotes syntax requires to have |
If you have a rhsTerm.asExpr match
case '{ $rhs: t } =>
lazyVal[t]("myValName", rhs){ x => '{ println(v) } } // `[t]` can be iferred |
Recovering an |
Not sure when it is not sufficient. Could you provide an example? We can use rhsTerm.asExpr match
case '{ $rhs: t } => '{ lazy val myValName: t = $rhs; println(v) } |
|
Both those cases are possible and covered in the matching-types section of the Macro Tutorial. To do rhsTerm.asExpr match
case '{ $rhs: t } =>
// The type of `rhs` is statically known as `t`
// A given `Type[t]` is available here
rhsTerm.asExprOf[t] // ok
'{ val x: t = $rhs; ... } // `t` statically known to be the given `Type[t]` Alternatively we could do rhsTerm.tpe match
case '[t] =>
// A given `Type[t]` is available here
val rhs = rhsTerm.asExprOf[t] // ok
'{ val x: t = $rhs; ... } // `t` statically known to be the given `Type[t]` Methods and field/method can also be statically known trait Foo:
def foo: Int = 2 rhsTerm.asExpr match
case '{ expr: Foo } =>
'{ $expr.foo } or to get the precise type rhsTerm.asExpr match
case '{ type t <: Foo; expr: `t` } =>
'{ $expr.foo } |
We are not speaking of the same thing. v match {
case '{ $rhs: t } =>
'{
val tv: t = $rhs
tv.foreach { inner => println("inner=" + inner) }
/*
[error] ^^^^^^^^^
[error] value foreach is not a member of t.
*/
}
}
If it's possible to write such constraints |
Not related to this PR specifically, but I think the documentation could more clearly state, that the quote type matching could be use to extract static type from inline def foo[T](v: Any): Unit = ${ fooImpl[T]('v) }
private def fooImpl[T: Type](v: Expr[Any])(using q: Quotes): Expr[Unit] = {
import q.reflect.*
TypeRepr.of[T].asType match {
case '[t] =>
val vt = Type.of[t]
val typedExpr = v.asExprOf[t](using vt)
'{
val ve: t = ${typedExpr}
println(s"ve = $ve")
}
}
} |
Related to #13929
Currently
ValDef.let
doesn't allow to defineFlags
for theval
definition.Usage:
In this way, it's possible to create an
Ref
to theval
before its definition (required for recursive/lazy definitions).