Skip to content
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

[WIP] support operator interception for non-literal types #147

Closed
wants to merge 5 commits into from

Conversation

erikerlandson
Copy link
Contributor

goal is to support the ability for OpMacro to attempt a call to implicitly[OpIntercept[op, arg, arg...]] when it cannot resolve an operator with its arguments. See discussion on #140.

@erikerlandson
Copy link
Contributor Author

Example run of current code:

scala> import singleton.ops.impl._, singleton.ops.impl.Rig._
import singleton.ops.impl._
import singleton.ops.impl.Rig._

scala> implicitly[Add[Rig[2], Rig[3]]]
usingFuncName: opTpe= singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,2,3,singleton.ops.NP]
  funcType= trait +
  opResult= CalcLit(Int,5)
res0: singleton.ops.impl.Rig.Add[singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3]] = singleton.ops.impl.Rig$Add$$anon$3@6fc0a38a

scala> res0.value
res1: res0.Out = Rig(5)

scala> implicitly[OpIntercept[OpId.+, Rig[2], Rig[3], 0]]
usingFuncName: opTpe= singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,2,3,singleton.ops.NP]
  funcType= trait +
  opResult= CalcLit(Int,5)
res2: singleton.ops.impl.OpIntercept[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],0] = singleton.ops.impl.Rig$$anon$2@3320bafa

scala> res2.value
res3: res2.Out = Rig(5)

scala> implicitly[Rig[2] + Rig[3]]
usingFuncName: opTpe= singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,2,3,singleton.ops.NP]
  funcType= trait +
  opResult= CalcLit(Int,5)


itree= singleton.ops.impl.OpIntercept[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],Int(0)]


usingFuncName: opTpe= singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],singleton.ops.NP]
  funcType= trait +
  opResult= CalcUnknown(singleton.ops.impl.OpIntercept[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],Int(0)],Some(scala.Predef.implicitly[singleton.ops.impl.OpIntercept[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],Int(0)]](singleton.ops.impl.Rig.rigAddition[singleton.ops.impl.Rig[2], singleton.ops.impl.Rig[3], singleton.ops.impl.Rig[this.Out]](Rig.this.Add.addRig[2, 3, this.Out](impl.this.OpInt.impl[2 + 3]({
  final class $anon extends AnyRef with singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,2,3,singleton.ops.NP] {
    def <init>(): <$anon: singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,2,3,singleton.ops.NP]> = {
      $anon.super.<init>();
      ()
    };
    type OutWide = Int;
    type Out = Int(5);
    type OutInt = Int(5);
    final private[this] val value: Int(5) = 5;
    final <stable> <accessor> def value: Int(5) = $anon.this.value;
    final private[this] val isLiteral: Boolean(true) = true;
    final <stable> <accessor> def isLiteral: Boolean(true) = $anon.this.isLiteral;
    final private[this] val valueWide: Int = 5;
    final <stable> <accessor> def valueWide: Int = $anon.this.valueWide
  };
  new $anon()
}))))))


stack trace:
  singleton.ops.impl.GeneralMacros.abort(GeneralMacros.scala:658)
  singleton.ops.impl.GeneralMacros.abort$(GeneralMacros.scala:657)
  singleton.ops.impl.OpMacro$Macro.abort(OpMacros.scala:92)
  singleton.ops.impl.GeneralMacros.extractionFailed(GeneralMacros.scala:757)
  singleton.ops.impl.GeneralMacros.extractionFailed$(GeneralMacros.scala:755)
  singleton.ops.impl.OpMacro$Macro.extractionFailed(OpMacros.scala:92)
  singleton.ops.impl.GeneralMacros$MaterializeOpAuxGen.usingFuncName(GeneralMacros.scala:1405)
  singleton.ops.impl.OpMacro$Macro.impl(OpMacros.scala:99)


                 ^
       error: Cannot extract value from singleton.ops.impl.OpMacro[singleton.ops.impl.OpId.+,singleton.ops.impl.Rig[2],singleton.ops.impl.Rig[3],singleton.ops.NP]
       showRaw==> TypeRef(ThisType(singleton.ops.impl), singleton.ops.impl.OpMacro, List(TypeRef(SingleType(ThisType(singleton.ops.impl), singleton.ops.impl.OpId), singleton.ops.impl.OpId.$plus, List()), TypeRef(ThisType(singleton.ops.impl), singleton.ops.impl.Rig, List(LiteralType(Constant(2)))), TypeRef(ThisType(singleton.ops.impl), singleton.ops.impl.Rig, List(LiteralType(Constant(3)))), TypeRef(SingleType(SingleType(SingleType(ThisType(<root>), singleton), singleton.ops), singleton.ops.package), TypeName("NP"), List())))

@soronpo
Copy link
Collaborator

soronpo commented Jun 10, 2020

OK, I know the reason. Indeed, as you suspected the usingFuncName is failing since it's receiving a CalcUnknown and in not of a special case it's designed to handle. I propose that you:

  1. Add a CalcOpIntercept here:
    case class CalcUnknown(tpe : Type, treeOption : Option[Tree]) extends Calc {
  case class CalcOpIntercept(tpe : Type, tree : Tree) extends Calc {
    override val primitive: Primitive = Primitive.Unknown(tpe, "OpIntercept")
  }
  1. In your change under unsupported, return CalcOpIntercept instead of CalcUnkown.
  2. Add another special case handling in usingFuncName.
  3. You should comb the code for where CalcUnknown is currently used and see if another case for CalcOpIntercept should be added (or maybe they should have common ancestry to be handled together).

@erikerlandson
Copy link
Contributor Author

Thanks, I'll look into that. I think I may also be loading CalcUnknown with the wrong type and tree from the call to implicitly

@erikerlandson
Copy link
Contributor Author

erikerlandson commented Jun 11, 2020

I think I may also be loading CalcUnknown with the wrong type and tree from the call to implicitly

Yeah, IIUC, I think I should be loading something more like the implicitly[...].Out into the type and possibly None for the value tree.

On a related note, subclassing OpIntercept under OpMacro forces me to compute a value for my custom types (e.g. Fraction), which feels dubious to me because (1) there may not be a corresponding value for the desired type output in the case of non-literal types, and (2) even if I do augment implicit details to create such a value, actually accessing that value inside of GeneralMacros is edging back into c.eval instead of just c.typecheck

@soronpo
Copy link
Collaborator

soronpo commented Jun 11, 2020

Yeah, IIUC, I think I should be loading something more like the implicitly[...].Out into the type and possibly None for the value tree.

Add support for OpIntercept symbol here:

case TypeRef(_, sym, ft :: tp :: _) if sym == opMacroSym && ft.typeSymbol == funcTypes.GetType =>

This will allow to get the Out.
I think it's possible to generalize it properly by checking if its a subtype/subclass.

On a related note, subclassing OpIntercept under OpMacro forces me to compute a value for my custom types (e.g. Fraction), which feels dubious to me because (1) there may not be a corresponding value for the desired type output in the case of non-literal types, and (2) even if I do augment implicit details to create such a value, actually accessing that value inside of GeneralMacros is edging back into c.eval instead of just c.typecheck

I don't see how is this related to c.eval.

@soronpo
Copy link
Collaborator

soronpo commented Jun 11, 2020

You know what, leave it to me, I'll try to do this over the weekend, and you can finish the fraction on top.

@erikerlandson
Copy link
Contributor Author

erikerlandson commented Jun 11, 2020

I'll try to do this over the weekend, and you can finish the fraction on top.

OK, thanks!

@erikerlandson
Copy link
Contributor Author

@soronpo did you have a chance to play with this at all?

@soronpo
Copy link
Collaborator

soronpo commented Jun 17, 2020

@soronpo did you have a chance to play with this at all?

Sorry, still have too much on my plate. I'll get there soon though.

@soronpo
Copy link
Collaborator

soronpo commented Jun 20, 2020

Starting to work on it

@erikerlandson
Copy link
Contributor Author

closing this in favor of #149

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants