aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/printing/RefinedPrinter.scala
blob: 9fc8cb513e3208d5d307548ced48ef1adf76c05c (plain) (tree)
1
2
3
4
5
6
7
8
9



                        
                                                                            

                                                                                     

                         


                                                                
 

                                                       

                                                                               
                                                                
                                                        

                                                               
                            




                                    




                                                 

                                                                    


                                                                  
                                                                


                        




                                                           



                                                                
                                                                       




                       


                                                          
                                             








                                                         




                                                                               




                                                                                             
     






                                                    
                                                               











                                                     
                                                                          






                                                                                  





                                                    

                                                                          








                                                            

                                                            
                                                                

                                                               
                                                                           

                                                                                  
                                               

                                     
                                                         



                                                            




                                                               
                                                                         
                                                                                             
 




                                                           










                                                                                         

                  
                                
                                          

                                   
                            
                                                                                                     

                                
                                
                                                                                 













                                                                  

                                                                   







                                                                         
                                                                                                                              
         
                                  

                                                                              





                                                                                        
                                                                     







                                                                                                       
                               

                                            
                                                                










                                                             
                                                               








                                                                     

                                                                              

                                                             

                                                                                         
         
                                             
                       






                                                                                                   

                                      

                                                  
           
         

                                                                                      
                          
                                          
                
                                            
                                                                                     
                                                             
           






                                                                                      
                                     
                                                       









                                                                       
                                                        





                                                                                             
                                            
                       


                                
                            
                 
                                         


                                                                
                            
                 
                                                    







                                                                                                       
                                  
                                         
                                              



                                                                                           
                                                            









                                                                                   
                               

                                                                             
                              
                                                              
                             
                                                            
                       
                                   
                       
                                          
                                 
                                                                                  
                                 
                                                                                  
                                   
                                       
                                
                                    
                                
                                           
                                 
                                          
                                             
                                                 
                                
         
                                          
                                                                         
                                 

                                                       


                                 







                                                                                                 

                                                                                











                                                                      
































                                                                                   
                               




                                                                              

                                             
 
package dotty.tools.dotc
package printing

import core._
import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._
import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation
import StdNames.nme
import ast.{Trees, untpd}
import Trees._
import scala.annotation.switch

class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {

  override protected def recursionLimitExceeeded() = {}

  protected val PrintableFlags = (ModifierFlags | Label | Module).toCommonFlags

  /** The closest enclosing DefDef, TypeDef, or ClassDef node */
  private var currentOwner: untpd.Tree = untpd.EmptyTree

  def atOwner(owner: Tree[_ >: Untyped])(op: => Text): Text = {
    val saved = currentOwner
    currentOwner = owner
    try op
    finally { currentOwner = saved }
  }

  private def ownerIsClass = currentOwner match {
    case owner: TypeDef[_] => owner.isClassDef
    case owner: untpd.ModuleDef => true
    case _ => false
  }

  override def nameString(name: Name): String = name.decode.toString

  override protected def simpleNameString(sym: Symbol): String = {
    var name = sym.originalName
    //if (sym is ModuleClass) name = name.stripModuleClassSuffix
    name.decode.toString
  }

  override protected def fullNameOwner(sym: Symbol) = {
    val owner = super.fullNameOwner(sym)
    if (owner is ModuleClass) owner.sourceModule else owner
  }

  override def toTextRef(tp: SingletonType): Text = controlled {
    tp match {
      case ThisType(cls) =>
        if (cls.isAnonymousClass) return "this"
        if (cls is ModuleClass) return fullNameString(cls.sourceModule)
      case _ =>
    }
    super.toTextRef(tp)
  }

  override def toTextPrefix(tp: Type): Text = controlled {
    tp match {
      case ThisType(cls) =>
        if (isOmittablePrefix(cls)) return ""
      case tp @ TermRef(pre, name) =>
        val sym = tp.symbol
        if (sym.isPackageObject) return toTextPrefix(pre)
        if (isOmittablePrefix(sym)) return ""
      case _ =>
    }
    super.toTextPrefix(tp)
  }

  override protected def refinementNameString(tp: RefinedType): String =
    if (tp.parent.isInstanceOf[WildcardType] || tp.refinedName == nme.WILDCARD)
      super.refinementNameString(tp)
    else {
      val tsym = tp.member(tp.refinedName).symbol
      if (!tsym.exists) super.refinementNameString(tp)
      else {
        val name = tsym.originalName
        nameString(if (tsym is ExpandedTypeParam) name.asTypeName.unexpandedName() else name)
      }
    }

  override def toText(tp: Type): Text = controlled {
    def toTextTuple(args: List[Type]): Text =
      "(" ~ toTextGlobal(args, ", ") ~ ")"
    def toTextFunction(args: List[Type]): Text =
      changePrec(GlobalPrec) {
        val argStr: Text =
          if (args.length == 2 && !defn.isTupleType(args.head))
            atPrec(InfixPrec) { toText(args.head) }
          else
            toTextTuple(args.init)
        argStr ~ " => " ~ toText(args.last)
      }
    tp match {
      case tp: RefinedType =>
        val args = tp.typeArgs
        if (args.nonEmpty) {
          val tycon = tp.unrefine
          val cls = tycon.typeSymbol
          if (cls.typeParams.length == args.length) {
            if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*"
            if (cls == defn.ByNameParamClass) return "=> " ~ toText(args.head)
            if (defn.FunctionClasses contains cls) return toTextFunction(args)
            if (defn.TupleClasses contains cls) return toTextTuple(args)
          }
          return (toTextLocal(tycon) ~ "[" ~ toTextGlobal(args, ", ") ~ "]").close
        }
      case tp @ TypeRef(pre, name) =>
        if (tp.symbol is TypeParam | TypeArgument) {
          return tp.info match {
            case TypeAlias(hi) => toText(hi)
            case _ => nameString(tp.symbol)
          }
        }
      case typer.Inferencing.FunProto(args, resultType, _) =>
        "funproto(" ~ toTextGlobal(args, ", ") ~ "):" ~ toText(resultType)
      case _ =>
    }
    super.toText(tp)
  }

  override def toText[T >: Untyped](tree: Tree[T]): Text = {

    def optDotPrefix(name: Name) = optText(name)(_ ~ ".")

    def optAscription(tpt: Tree[T]) = optText(tpt)(": " ~ _)

    def tparamsText[T >: Untyped](params: List[Tree[T]]): Text =
      "[" ~ toText(params, ", ") ~ "]" provided params.nonEmpty

    def addVparamssText(txt: Text, vparamss: List[List[ValDef[T]]]): Text =
      (txt /: vparamss)((txt, vparams) => txt ~ "(" ~ toText(vparams, ", ") ~ ")")

    def blockText(trees: List[Tree[T]]): Text =
      "{" ~ toText(trees, "\n") ~ "}"

    def caseBlockText(tree: Tree[T]): Text = tree match {
      case Block(stats, expr) => toText(stats :+ expr, "\n")
      case expr => toText(expr)
    }

    def enumText(tree: Tree[T]) = tree match {
      case _: untpd.GenFrom | _: untpd.GenAlias => toText(tree)
      case _ => "if " ~ toText(tree)
    }

    def forText(enums: List[Tree[T]], expr: Tree[T], sep: String): Text =
      changePrec(GlobalPrec) { "for " ~ Text(enums map enumText, "; ") ~ sep ~ toText(expr) }

    def cxBoundToText(bound: Tree[T]): Text = bound match {
      case AppliedTypeTree(tpt, _) => " : " ~ toText(tpt)
      case untpd.Function(_, tpt) => " <% " ~ toText(tpt)
    }

    def constrText(tree: Tree[T]): Text = toTextLocal(tree).stripPrefix("new ")

    def annotText(tree: Tree[T]): Text = "@" ~ constrText(tree)

    def modText(mods: Modifiers[T], kw: String): Text = {
      val suppressKw = if (ownerIsClass) mods is ParamAndLocal else mods is Param
      val flagMask = if (suppressKw) PrintableFlags &~ Private else PrintableFlags
      val modsText: Text = (mods.flags & flagMask).toString
      Text(mods.annotations.map(annotText), " ") ~~ modsText ~~ (kw provided !suppressKw)
    }

    import untpd._

    var txt: Text = tree match {
      case id: Trees.BackquotedIdent[_] =>
        "`" ~ toText(id.name) ~ "`"
      case Ident(name) =>
        tree.typeOpt match {
          case tp: NamedType if name != nme.WILDCARD => toTextPrefix(tp.prefix) ~ selectionString(tp)
          case _ => toText(name)
        }
      case Select(qual, name) =>
        toTextLocal(qual) ~ ("." ~ toText(name) provided name != nme.CONSTRUCTOR)
      case This(name) =>
        optDotPrefix(name) ~ "this"
      case Super(This(name), mix) =>
        optDotPrefix(name) ~ "super" ~ optText(mix)("[" ~ _ ~ "]")
      case Apply(fun, args) =>
        toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
      case TypeApply(fun, args) =>
        toTextLocal(fun) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
      case Literal(c) =>
        toText(c)
      case New(tpt) =>
        "new " ~ toTextLocal(tpt)
      case Pair(l, r) =>
        "(" ~ toTextGlobal(l) ~ ", " ~ toTextGlobal(r) ~ ")"
      case Typed(expr, tpt) =>
        changePrec(InfixPrec) { toText(expr) ~ ": " ~ toText(tpt) }
      case NamedArg(name, arg) =>
        toText(name) ~ " = " ~ toText(arg)
      case Assign(lhs, rhs) =>
        changePrec(GlobalPrec) { toTextLocal(lhs) ~ " = " ~ toText(rhs) }
      case Block(stats, expr) =>
        blockText(stats :+ expr)
      case If(cond, thenp, elsep) =>
        changePrec(GlobalPrec) {
          "if " ~ toText(cond) ~ (" then" provided !cond.isInstanceOf[Parens]) ~~ toText(thenp) ~ optText(elsep)(" else " ~ _)
        }
      case Closure(env, ref, _) =>
        "closure(" ~ (toTextGlobal(env, ", ") ~ " | " provided env.nonEmpty) ~
        toTextGlobal(ref) ~ ")"
      case Match(sel, cases) =>
        if (sel.isEmpty) blockText(cases)
        else changePrec(GlobalPrec) { toText(sel) ~ " match " ~ blockText(cases) }
      case CaseDef(pat, guard, body) =>
        "case " ~ toText(pat) ~ optText(guard)("if " ~ _) ~ " => " ~ caseBlockText(body)
      case Return(expr, from) =>
        changePrec(GlobalPrec) { "return " ~ optText(expr)(" " ~ _) }
      case Try(expr, handler, finalizer) =>
        changePrec(GlobalPrec) {
          "try " ~ toText(expr) ~ optText(handler)(" catch " ~ _) ~ optText(finalizer)(" finally " ~ _)
        }
      case Throw(expr) =>
        changePrec(GlobalPrec) {
          "throw " ~ toText(expr)
        }
      case SeqLiteral(elems) =>
        "[" ~ toTextGlobal(elems, ",") ~ "]"
      case TypeTree(orig) =>
        if (tree.hasType) toText(tree.typeOpt) else toText(orig)
      case SingletonTypeTree(ref) =>
        toTextLocal(ref) ~ ".type"
      case SelectFromTypeTree(qual, name) =>
        toTextLocal(qual) ~ "#" ~ toText(name)
      case AndTypeTree(l, r) =>
        changePrec(AndPrec) { toText(l) ~ " & " ~ toText(r) }
      case OrTypeTree(l, r) =>
        changePrec(OrPrec) { toText(l) ~ " | " ~ toText(r) }
      case RefinedTypeTree(tpt, refines) =>
        toTextLocal(tpt) ~ " " ~ blockText(refines)
      case AppliedTypeTree(tpt, args) =>
        toTextLocal(tpt) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
      case TypeBoundsTree(lo, hi) =>
        optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _)
      case Bind(name, body) =>
        changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) }
      case Alternative(trees) =>
        changePrec(OrPrec) { toText(trees, " | ") }
      case UnApply(fun, args) =>
        toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
      case ValDef(mods, name, tpt, rhs) =>
        modText(mods, if (mods is Mutable) "var" else "val") ~~ toText(name) ~
          optAscription(tpt) ~ optText(rhs)(" = " ~ _)
      case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
        atOwner(tree) {
          val first = modText(mods, "def") ~~ toText(name) ~ tparamsText(tparams)
          addVparamssText(first, vparamss) ~ optAscription(tpt) ~ optText(rhs)(" = " ~ _)
        }
      case tree @ TypeDef(mods, name, rhs) =>
        atOwner(tree) {
          def typeDefText(rhsText: Text) =
            modText(mods, "type") ~~ toText(name) ~ tparamsText(tree.tparams) ~ rhsText
          rhs match {
            case impl: Template =>
              modText(mods, if (mods is Trait) "trait" else "class") ~~ toText(name) ~ toText(impl)
            case rhs: TypeBoundsTree =>
              typeDefText(toText(rhs))
            case rhs: TypeTree =>
              typeDefText(toText(rhs))
            case _ =>
              typeDefText(optText(rhs)(" = " ~ _))
          }
        }
      case Template(DefDef(mods, _, tparams, vparamss, _, _), parents, self, stats) =>
        val tparamsTxt = tparamsText(tparams)
        val prefix: Text =
          if (vparamss.isEmpty) tparamsTxt
          else {
            var modsText = modText(mods, "")
            if (mods.hasAnnotations && !mods.hasFlags) modsText = modsText ~~ " this"
            addVparamssText(tparamsTxt ~~ modsText, vparamss)
          }
        val parentsText = Text(parents map constrText, " with ")
        val selfText = {
          val selfName = if (self.name == nme.WILDCARD) "this" else self.name.toString
          (selfName ~ optText(self.tpt)(": " ~ _) ~ " =>").close
        } provided !self.isEmpty
        val bodyText = "{" ~~ selfText ~~ toTextGlobal(stats, "\n") ~ "}"
        prefix ~~ (" extends" provided ownerIsClass) ~~ parentsText ~~ bodyText
      case Import(expr, selectors) =>
        def selectorText(sel: Tree): Text = sel match {
          case Pair(l, r) => toTextGlobal(l) ~ " => " ~ toTextGlobal(r)
          case _ => toTextGlobal(sel)
        }
        val selectorsText: Text = selectors match {
          case Ident(name) :: Nil => toText(name)
          case _ => "{" ~ Text(selectors map selectorText, ", ") ~ "}"
        }
        "import " ~ toTextLocal(expr) ~ "." ~ selectorsText
      case PackageDef(pid, stats) =>
        val statsText = stats match {
          case (pdef: PackageDef) :: Nil => toText(pdef)
          case _ => toTextGlobal(stats, "\n")
        }
        val bodyText =
          if (currentPrecedence == TopLevelPrec) "\n" ~ statsText else " {" ~ statsText ~ "}"
        "package " ~ toTextLocal(pid) ~ bodyText
      case Annotated(annot, arg) =>
        toTextLocal(arg) ~~ annotText(annot)
      case EmptyTree =>
        "<empty>"
      case SharedTree(shared) =>
        toText(shared)
      case TypedSplice(t) =>
        toText(t)
      case ModuleDef(mods, name, impl) =>
        atOwner(tree) {
          modText(mods, "object") ~~ toText(name) ~ toText(impl)
        }
      case SymbolLit(str) =>
        "'" + str
      case InterpolatedString(id, strings, elems) =>
        def interleave(strs: List[Text], elems: List[Text]): Text = ((strs, elems): @unchecked) match {
          case (Nil, Nil) => ""
          case (str :: Nil, Nil) => str
          case (str :: strs1, elem :: elems1) => str ~ elem ~ interleave(strs1, elems1)
        }
        val strTexts = strings map (str => Str(escapedString(str.const.stringValue)))
        val elemsTexts = elems map (elem => "{" ~ toTextGlobal(elem) ~ "}")
        toText(id) ~ "\"" ~ interleave(strTexts, elemsTexts) ~ "\""
      case Function(args, body) =>
        var implicitSeen: Boolean = false
        def argToText(arg: Tree) = arg match {
          case ValDef(mods, name, tpt, _) =>
            val implicitText =
              if ((mods is Implicit) && !implicitSeen) { implicitSeen = true; "implicit " }
              else ""
            implicitText ~ toText(name) ~ optAscription(tpt)
          case _ =>
            toText(arg)
        }
        val argsText = args match {
          case (arg @ ValDef(_, _, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg)
          case _ => "(" ~ Text(args map argToText, ", ") ~ ")"
        }
        changePrec(GlobalPrec) {
          argsText ~ " => " ~ toText(body)
        }
      case InfixOp(l, op, r) =>
        val opPrec = parsing.precedence(op)
        changePrec(opPrec) { toText(l) ~ " " ~ toText(op) ~ " " ~ toText(r) }
      case PostfixOp(l, op) =>
        changePrec(InfixPrec) { toText(l) ~ " " ~ toText(op) }
      case PrefixOp(op, r) =>
        changePrec(DotPrec) { toText(op) ~ " " ~ toText(r) }
      case Parens(t) =>
        "(" ~ toTextGlobal(t) ~ ")"
      case Tuple(ts) =>
        "(" ~ toTextGlobal(ts, ", ") ~ ")"
      case WhileDo(cond, body) =>
        changePrec(GlobalPrec) { "while " ~ toText(cond) ~ " do " ~ toText(body) }
      case DoWhile(cond, body) =>
        changePrec(GlobalPrec) { "do " ~ toText(body) ~ " while " ~ toText(cond) }
      case ForYield(enums, expr) =>
        forText(enums, expr, " yield ")
      case ForDo(enums, expr) =>
        forText(enums, expr, " do ")
      case GenFrom(pat, expr) =>
        toText(pat) ~ " <- " ~ toText(expr)
      case GenAlias(pat, expr) =>
        toText(pat) ~ " = " ~ toText(expr)
      case ContextBounds(bounds, cxBounds) =>
        (toText(bounds) /: cxBounds) {(t, cxb) =>
          t ~ cxBoundToText(cxb)
        }
      case PatDef(mods, pats, tpt, rhs) =>
        modText(mods, "val") ~~ toText(pats, ", ") ~ optAscription(tpt) ~
          optText(rhs)(" = " ~ _)
      case Thicket(trees) =>
        "Thicket {" ~~ toTextGlobal(trees, "\n") ~~ "}"
      case _ =>
        tree.fallbackToText(this)
    }
    if (ctx.settings.printtypes.value && tree.hasType) {
      val tp = tree.typeOpt match {
        case tp: TermRef if tree.isInstanceOf[RefTree] && !tp.denot.isOverloaded => tp.underlying
        case tp => tp
      }
      if (tree.isType) txt = toText(tp)
      else if (!tree.isDef) txt = "<" ~ txt ~ ":" ~ toText(tp) ~ ">"
    }
    if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]])
      txt = txt ~ "@" ~ tree.pos.toString
    tree match {
      case Block(_, _) | Template(_, _, _, _) => txt
      case _ => txt.close
    }
  }

  def optText(name: Name)(encl: Text => Text): Text =
    if (name.isEmpty) "" else encl(toText(name))

  def optText[T >: Untyped](tree: Tree[T])(encl: Text => Text): Text =
    if (tree.isEmpty) "" else encl(toText(tree))

  override protected def polyParamName(name: TypeName): TypeName =
    name.unexpandedName()

  override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam

  override protected def treatAsTypeArg(sym: Symbol) =
    sym.isType && (sym is ProtectedLocal) &&
      (sym.allOverriddenSymbols exists (_ is TypeParam))

  override protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type =
    (parent /: parent.classSymbol.typeParams) { (parent, tparam) =>
      val targSym = cls.decls.lookup(tparam.name)
      if (targSym.exists) RefinedType(parent, targSym.name, targSym.info)
      else parent
    }

  override def kindString(sym: Symbol) = {
    val flags = sym.flagsUNSAFE
    if (flags is Package) "package"
    else if (sym.isPackageObject) "package object"
    else if (flags is Module) "object"
    else if (flags is ImplClass) "class"
    else if (sym.isClassConstructor) "constructor"
    else super.kindString(sym)
  }

  override protected def keyString(sym: Symbol): String = {
    val flags = sym.flagsUNSAFE
    if (sym.isType && (flags is ExpandedTypeParam)) ""
    else super.keyString(sym)
  }

  override def toTextFlags(sym: Symbol) = {
    var flags = sym.flagsUNSAFE
    if (flags is TypeParam) flags = flags &~ Protected
    Text(flags.flagStrings.filterNot(_.startsWith("<")) map stringToText, " ")
  }

  override def toText(denot: Denotation): Text = toText(denot.symbol)

  override def plain = new PlainPrinter(_ctx)
}