Skip to content

Inferred type refers to a local TermRef #2239

Closed
@liufengyun

Description

@liufengyun

The following code compiles fine with Scalac, but fails in Dotty. If the commented version of ~++ is used, everything is fine.

trait Rule[-In, +A] extends (In => A) {
  def flatMap[In2 <: In, B](fa2ruleb: A => Rule[In2, Seq[B]]): Rule[In, Seq[B]] = ???
  def map[B](fa2b: A => B): Rule[In, B] = ???

  def ~++[In2, B >: A](next: => Rule[In2, Seq[B]]) = for (a <- this; b <- next) yield a :: b.toList
  // def ~++[In2, B >: A](next: => Rule[In2, Seq[B]]): Rule[In, Seq[B]] = for (a <- this; b <- next) yield a :: b.toList
}

class SeqRule {
  type S
  type A
  def * : Rule[S, List[A]] = ???
  def +(rule: Rule[S, A]) : Rule[S, Seq[A]] = rule ~++ *
}

The cause is that ~++ gets an "ill" type that refers to the local variable b (see below at bottom). The check is not handled by Typer#escapingRefs. I tried to modify TypeOps#simplify to simplify TypeRef(TermRef(NoPrefix,b),scala$collection$TraversableOnce$$A) to just ParamRef(B), but didn't succeed.

PolyType(
  List(In2, B),

  List(TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,scala)),Nothing), TypeRef(ThisType(TypeRef(NoPrefix,scala)),Any)), TypeBounds(TypeRef(TermRef(NoPrefix,rule),Rule$$A), TypeRef(ThisType(TypeRef(NoPrefix,scala)),Any))),

  MethodType(
    List(next),
    List(
      ExprType(
        RefinedType(
          RefinedType(
            TypeRef(ThisType(TypeRef(NoPrefix,<empty>)),Rule),
            Rule$$In,
            TypeAlias(ParamRef(In2), -1)
          ),

          Rule$$A,
          TypeAlias(
            RefinedType(
              TypeRef(ThisType(TypeRef(NoPrefix,collection)),Seq),
              scala$collection$Seq$$A,
              TypeAlias(ParamRef(B), 1)
            ),
          1))
      )
    ),

    RefinedType(
      RefinedType(
        TypeRef(ThisType(TypeRef(NoPrefix,<empty>)),Rule),
        Rule$$In,
        TypeAlias(
          TypeRef(TermRef(NoPrefix,rule),Rule$$In),
        -1)
      ),

      Rule$$A,

      TypeAlias(
        RefinedType(
          TypeRef(ThisType(TypeRef(NoPrefix,collection)),Seq),
          scala$collection$Seq$$A,
          TypeAlias(TypeRef(TermRef(NoPrefix,b),scala$collection$TraversableOnce$$A), 1) <=== b !!
        ),
      1)
   )
  )
)

The expanded version of ~++ looks like follows:

    def ~++[In2, B >: A](next: => Rule[In2, Seq[B]]):
      Rule[In, scala.collection.Seq[B]]
     =
      this.flatMap[Nothing^, B^](
        {
          def $anonfun(a: A): Rule[Nothing^, scala.collection.Seq[B^]] =
            next.map[scala.collection.immutable.List[B]^](
              {
                def $anonfun(b: scala.collection.Seq[B]):
                  scala.collection.immutable.List[B]
                 =
                  {
                    val $1$: A = a
                    b.toList.::[B^]($1$)
                  }
                closure($anonfun)
              }
            )
          closure($anonfun)
        }
      )
  }

Note: this test case is a minimized version from the library json4s.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions