Skip to content

Fix TreeMap's transformTerm wrt UnApply #7503

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

Merged
merged 1 commit into from
Nov 7, 2019

Conversation

anatoliykmetyuk
Copy link
Contributor

UnApply <: Term however it cannot appear where
a term can. Hence we do not transform it from
transformTerm and guard against it getting into
transformTerm to prevent MatchErrors.

@anatoliykmetyuk anatoliykmetyuk self-assigned this Nov 5, 2019
@anatoliykmetyuk anatoliykmetyuk force-pushed the fix-treemap branch 5 times, most recently from 41f1d30 to 7171f6a Compare November 5, 2019 16:22
@@ -157,7 +157,7 @@ trait TreeUtils
}
}

def transformTerm(tree: Term)(given ctx: Context): Term = {
def transformTerm(tree: Term)(given ctx: Context): Term = if IsTerm.unapply(tree).isEmpty then tree else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't correct, if tree is a Term then IsTerm.unapply(tree) should never be empty. Where did that tree come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for this is (at least) the UnApply type. Technically it is <: Term but for the purposes of Tasty reflect we do not treat it as such since it cannot appear in a term position.

Copy link
Contributor Author

@anatoliykmetyuk anatoliykmetyuk Nov 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed earlier the failing example that this PR fixes:

Macro:

import scala.quoted.{ given, _ }

inline def mcr(x: => Unit): Unit = ${mcrImpl('x)}
def mcrImpl(x: Expr[Unit])(given ctx: QuoteContext): Expr[Unit] =
  import ctx.tasty.{ given, _ }
  val tr: Term = x.unseal
  object m extends TreeMap
  m.transformTerm(tr).seal.cast[Unit]

Test:

@main def Test = mcr {
  val (a, b) = ???
}

@anatoliykmetyuk
Copy link
Contributor Author

@nicolasstucki the problem seems to be with this method: https://github.com/lampepfl/dotty/blob/04a68b8df2c8f0bfe2f6fc41a7722b63a6dc4098/library/src-bootstrapped/scala/tasty/reflect/TreeUtils.scala#L113

val (a, b) = ??? is correctly represented in Tasty:

Representation
Inlined(
  EmptyTree,List(

  ),Block(
    List(
      ValDef(
        $1$,TypeTree[AppliedType(
          TypeRef(
            ThisType(
              TypeRef(
                NoPrefix,module class scala
              )
            ),class Tuple2
          ),List(
            TypeRef(
              ThisType(
                TypeRef(
                  NoPrefix,module class scala
                )
              ),class Nothing
            ), TypeRef(
              ThisType(
                TypeRef(
                  NoPrefix,module class scala
                )
              ),class Nothing
            )
          )
        )],Match(
          Typed(
            Ident(
              ???
            ),TypeTree[AnnotatedType(
              TypeRef(
                ThisType(
                  TypeRef(
                    NoPrefix,module class scala
                  )
                ),class Nothing
              ),ConcreteAnnotation(
                New(
                  TypeTree[TypeRef(
                    ThisType(
                      TypeRef(
                        NoPrefix,module class scala
                      )
                    ),class unchecked
                  )]
                )
              )
            )]
          ),List(
            CaseDef(
              Typed(
                UnApply(
                  TypeApply(
                    Select(
                      Ident(
                        Tuple2
                      ),unapply
                    ),List(
                      TypeTree[TypeRef(
                        ThisType(
                          TypeRef(
                            NoPrefix,module class scala
                          )
                        ),class Nothing
                      )], TypeTree[TypeRef(
                        ThisType(
                          TypeRef(
                            NoPrefix,module class scala
                          )
                        ),class Nothing
                      )]
                    )
                  ),List(

                  ),List(
                    Bind(
                      a,Ident(
                        _
                      )
                    ), Bind(
                      b,Ident(
                        _
                      )
                    )
                  )
                ),TypeTree[TypeRef(
                  ThisType(
                    TypeRef(
                      NoPrefix,module class scala
                    )
                  ),class Nothing
                )]
              ),EmptyTree,Apply(
                TypeApply(
                  Select(
                    Ident(
                      Tuple2
                    ),apply
                  ),List(
                    TypeTree[TypeRef(
                      ThisType(
                        TypeRef(
                          NoPrefix,module class scala
                        )
                      ),class Nothing
                    )], TypeTree[TypeRef(
                      ThisType(
                        TypeRef(
                          NoPrefix,module class scala
                        )
                      ),class Nothing
                    )]
                  )
                ),List(
                  Ident(
                    a
                  ), Ident(
                    b
                  )
                )
              )
            )
          )
        )
      ), ValDef(
        a,TypeTree[TypeRef(
          ThisType(
            TypeRef(
              NoPrefix,module class scala
            )
          ),class Nothing
        )],Select(
          Ident(
            $1$
          ),_1
        )
      ), ValDef(
        b,TypeTree[TypeRef(
          ThisType(
            TypeRef(
              NoPrefix,module class scala
            )
          ),class Nothing
        )],Select(
          Ident(
            $1$
          ),_2
        )
      )
    ),Literal(
      Constant(
        (

        )
      )
    )
  )
)

But transformTree method does not take the correct case at Typed(Unapply). This is because such a node passes the IsStatement check which goes before the IsUnapply check.

The `IsStatement` test before this commit
treated `Typed(Unapply)` nodes as statements, which is
not correct since they are patterns. They must pass
the `IsUnapply` test and fail `IsStatement` test.
However since they do not fail `IsStatement` test,
the `transformTree` method of `TreeMap` incorrectly
calls `transformStatement` on a `Typed(Unapply)`.
This commit makes the `IsStatement` test treat
the trees in question correctly.
@anatoliykmetyuk anatoliykmetyuk merged commit a923e6a into scala:master Nov 7, 2019
@anatoliykmetyuk anatoliykmetyuk deleted the fix-treemap branch November 7, 2019 16:46
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