Should transparent tuple be considered a literal

Heya! I’m playing with inlines (and they’re amazing!) for the first time and stumbled upon the following problem.

I have a derived typeclass with constant value:

trait Fields[P]:
  transparent inline def get = ("foo", "bar")

And then I’m trying to use it in an inline method:

inline def test[P](using f: Fields[P]) =
  inline if f.get.head == "foo" then "Your head is foo" else error("I need foo!")

This code does not compile because inline if cannot be reduced, however it does compile if I annotate get with literal type:

trait Fields[P]:
  transparent inline def get: ("foo", "bar") = ("foo", "bar")

So, I’m wondering if this is expected and if transparent works only with primitive types?

Just in case, I’d like to achieve a compile-type check of case class members:

case class Person(firstName: String, lastName: String)
test[Person]("firstName")        // This should compile
test[Person]("nope")             // This should not

This is as expected, what’s happening is that at the point of constructing the tuple its argument types are already widened to (String, String), so the transparent inline def is still taking the most precise type of the right-hand-side.

Take a look at Mirrors.

https://docs.scala-lang.org/scala3/reference/contextual/derivation.html#

Thanks, @bishabosha, I get that now it’s impossible. But I’m still curious if it’s already widened to (String, String) by design or because it’s just how it works now, i.e. can be a subject to change?

@hmf, yup, I already use mirrors to get the list of class members, but now I’m looking for a way to check at compile-time if a string present in a list (or a tuple, which is more likely to work out), i.e. I want some sort of compile-time List.contains. The YT channel is super cool by the way, never seen it before!

This is by design - all top level literal types are widened by default unless it is a final val or inline val. transparent inline def still widens but inline match is allowed to look at the type of the method body itself. By top level I mean the literal type would still be widened if it is the argument to some other type, e.g. List, or tuple types because the widening happens at the point of calling another constructor, method, etc.

There is SIP proposal #48 to let the user control when widening happens with a precise modifier on the type

2 Likes

Hmmm. When you said

By top level I mean the literal type would still be widened if it is the argument to some other type

It just stroke me that this might be somehow related to a bugreport I filled in yesterday (not related to the initial discourse post at all). If this is indeed related - what you’re saying might mean that the bugreport is false and what we’re trying to do there is impossible by design. If you by any chance can look at it - that’d be awesome.

Thanks!