Intersection of refinement types

I’m trying to implement a generalized Request class as a wrapper around a Play Request object with a fields member accessible via scala.Selectable.

The standard I’m using defines different API interactions having sharing some similarity in the headers the could feature, query parameter they allow etc.

For instance: There is are CRUD interactions which all allow a small set of common query parameters. On the other hand they differ in the kinds of headers they might contain.

To represent this variance I want to use a generic SelectableRequest class which implements scala.Selectable. For each of the unique headers, query parameters etc. I defined a refinement type on that class with a field corresponding to the value.

class SelectableRequest[+C](
  request: Request[C],
  elems: (String, Any)*
) extends WrappedRequest[C](request) with Selectable
{
  val fields: Map[String, Any] = elems.toMap

  def selectDynamic(name: String): Any = fields(name)
}

type SupportsETag[+C] = SelectableRequest[C] {
  val ETag: Option[String]
}

type SupportsIfNoneExist[+C] = SelectableRequest[C] {
  val IfNoneExist: Option[String]
}
...

I then represented request types as intersections of the refinement types.

type InteractionRequest[R] = WithResponseMediaType[R] & WithPretty[R] & WithSummary[R] & WithElements[R]

However, when using the new types the compiler cannot infer any fields of any of the composing refinement types. It only works if I use the refinement types themselves.

Is that intended behavior and I should use some other approach or is there a way to resolve this?

I’m using Intellij alongside the Scala plugin for my project (so if that is the issue than I’m sorry to have posted the question here).

What do you mean by “infer fields” ?

In particular, do you mean auto-completion ?
I was able to replicate this missing in Scastie (based on Metals, unlike the Intellij plugin):

(You’ll note both compile and run, even though auto-completion only works for the first one)

This seems to indicate the problem is earlier in the chain, maybe in the presentation compiler ? (This is more a question for other experts than the poster)

Thx for the answer. I’m aware that this does compile without issue, but didn’t state that clearly. I was just wondering why auto completion does not work in that case.

By “infer fields” I meant that I expected the compiler to be able to resolve the intersection type definition to the constituent types and then the set of fields (in my case) defined over all of the refinements would be made accessible via auto completion or some code insight feature.

Feel free to open a bug report for metals:

(I’m not 100% sure that’s the right place, but if not, I’m sure they’ll point you in the right direction)

If you need help opening a bug report, I’ll gladly help you

This might be more of a feature request. I made similar requests regarding enum / union type auto-completion for example (one got implemented!). This one (not by me but possibly relevant) is still open.

Maybe @tgodzik can chime in? Also try asking on Metals Discord.

I see what you mean, but I would still qualify it as a bug as I feel like the following should be equivalent:

A {def x: Int; def y: Int}
A {def x: Int} & A {def y: Int}

(Meaning in this context the completions for one should be identical, as they are the same type)
c.f. Scastie - An interactive playground for Scala.