<commit_before>package scala.meta
package semantic

import org.scalameta.adt._
import org.scalameta.annotations._
import org.scalameta.invariants._
import org.scalameta.unreachable
import scala.language.experimental.macros
import scala.{Seq => _}
import scala.annotation.compileTimeOnly
import scala.collection.immutable.Seq
import scala.reflect.{ClassTag, classTag}
import scala.meta.artifacts._
import scala.meta.prettyprinters._
import scala.meta.internal.{ast => impl} // necessary only to implement APIs, not to define them
import scala.meta.internal.{semantic => s} // necessary only to implement APIs, not to define them
import scala.meta.internal.{equality => e} // necessary only to implement APIs, not to define them
import scala.meta.internal.prettyprinters.Summary // necessary only to implement APIs, not to define them
import scala.meta.internal.ast.Helpers._ // necessary only to implement APIs, not to define them
import scala.reflect.runtime.{universe => ru} // necessary only for a very hacky approximation of hygiene

private[meta] trait Api {
  // ===========================
  // PART 1: PRETTYPRINTING
  // ===========================
  implicit def showSemantics[T <: Tree](implicit c: SemanticContext): Semantics[T] = scala.meta.internal.prettyprinters.TreeSemantics.apply[T](c)

  // ===========================
  // PART 2: EQUALITY
  // ===========================

  implicit class XtensionTypecheckingEquality[T1 <: Tree](tree1: T1) {
    @hosted def =:=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = e.Typechecking.equals(tree1, tree2)
    @hosted def =!=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = !e.Typechecking.equals(tree1, tree2)
  }

  implicit class XtensionNormalizingEquality[T1 <: Tree](tree1: T1) {
    @hosted def =~=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = e.Normalizing.equals(tree1, tree2)
    // TODO: what would be the symbol to express negation of =~=?
  }

  // ===========================
  // PART 3: CONFIGURATION
  // ===========================

  @hosted def dialect: Dialect = implicitly[SemanticContext].dialect

  @hosted def domain: Domain = implicitly[SemanticContext].domain

  implicit class XtensionDomainLikeContext(c: SemanticContext) {
    def sources: Seq[Source] = c.domain.sources
    def resources: Seq[Resource] = c.domain.resources
  }

  // ===========================
  // PART 4: ATTRIBUTES
  // ===========================

  implicit class XtensionSemanticTermDesugar(tree: Term) {
    @hosted def desugar: Term = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term]
      ttree.expansion match {
        case s.Expansion.Zero => unreachable
        case s.Expansion.Identity => ttree
        case s.Expansion.Desugaring(desugaring) => desugaring
      }
    }
  }

  implicit class XtensionSemanticTermTpe(tree: Term) {
    @hosted def tpe: Type = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term]
      ttree.typing match {
        case s.Typing.Zero => unreachable
        case s.Typing.Recursive => impl.Type.Singleton(tree.require[impl.Term.Ref]).setTypechecked
        case s.Typing.Nonrecursive(tpe) => tpe.require[impl.Type]
      }
    }
  }

  implicit class XtensionSemanticMemberTpe(tree: Member) {
    @hosted private def SeqRef: impl.Type.Name = {
      val sScala = s.Symbol.Global(s.Symbol.RootPackage, "scala", s.Signature.Term)
      val sCollection = s.Symbol.Global(sScala, "collection", s.Signature.Term)
      val sSeq = s.Symbol.Global(sCollection, "Seq", s.Signature.Type)
      impl.Type.Name("Seq").withAttrs(s.Denotation.Single(s.Prefix.Zero, sSeq)).setTypechecked
    }
    @hosted private def paramType(tree: impl.Term.Param): Type = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term.Param]
      ttree.typing match {
        case s.Typing.Zero => unreachable
        case s.Typing.Recursive => unreachable
        case s.Typing.Nonrecursive(impl.Type.Arg.ByName(tpe)) => impl.Type.Apply(SeqRef, List(tpe)).setTypechecked
        case s.Typing.Nonrecursive(impl.Type.Arg.Repeated(tpe)) => tpe
        case s.Typing.Nonrecursive(tpe: impl.Type) => tpe
      }
    }
    @hosted private def methodType(tparams: Seq[Type.Param], paramss: Seq[Seq[Term.Param]], ret: Type): Type = {
      if (tparams.nonEmpty) {
        val monoret = methodType(Nil, paramss, ret.require[impl.Type]).require[impl.Type]
        impl.Type.Lambda(tparams.require[Seq[impl.Type.Param]], monoret).setTypechecked
      } else paramss.foldRight(ret.require[impl.Type])((params, acc) => {
        val paramtypes = params.map(p => paramType(p.require[impl.Term.Param]).require[impl.Type.Arg])
        impl.Type.Function(paramtypes, acc).setTypechecked
      })
    }
    @hosted private def ctorType(owner: Member, paramss: Seq[Seq[Term.Param]]): Type = {
      val tparams = owner.tparams
      val ret = {
        if (tparams.nonEmpty) impl.Type.Apply(owner.tpe.require[impl.Type], tparams.map(_.name.require[impl.Type.Name]))
        else owner.tpe
      }.setTypechecked
      methodType(tparams, paramss, ret)
    }
    @hosted def tpe: Type = tree.require[impl.Member] match {
      case tree: impl.Pat.Var.Term => tree.name.tpe
      case tree: impl.Pat.Var.Type => tree.name
      case tree: impl.Decl.Def => methodType(tree.tparams, tree.paramss, tree.decltpe)
      case tree: impl.Decl.Type => tree.name
      case tree: impl.Defn.Def => methodType(tree.tparams, tree.paramss, tree.decltpe.getOrElse(tree.body.tpe))
      case tree: impl.Defn.Macro => methodType(tree.tparams, tree.paramss, tree.decltpe)
      case tree: impl.Defn.Type => tree.name
      case tree: impl.Defn.Class => tree.name
      case tree: impl.Defn.Trait => tree.name
      case tree: impl.Defn.Object => impl.Type.Singleton(tree.name).setTypechecked
      case       impl.Pkg(name: impl.Term.Name, _) => impl.Type.Singleton(name).setTypechecked
      case       impl.Pkg(impl.Term.Select(_, name: impl.Term.Name), _) => impl.Type.Singleton(name).setTypechecked
      case tree: impl.Pkg.Object => impl.Type.Singleton(tree.name).setTypechecked
      case tree: impl.Term.Param if tree.parent.map(_.isInstanceOf[impl.Template]).getOrElse(false) => ??? // TODO: don't forget to intersect with the owner type
      case tree: impl.Term.Param => paramType(tree)
      case tree: impl.Type.Param => tree.name.require[Type.Name]
      case tree: impl.Ctor.Primary => ctorType(tree.owner.require[Member], tree.paramss)
      case tree: impl.Ctor.Secondary => ctorType(tree.owner.require[Member], tree.paramss)
    }
  }

  implicit class XtensionSemanticRefDefn(tree: Ref) {
    @hosted def defns: Seq[Member] = implicitly[SemanticContext].defns(tree)
    @hosted def defn: Member = {
      defns match {
        case Seq(single) => single
        case Seq(_, _*) => throw new SemanticException(s"multiple definitions found for ${showSummary(tree)}")
        case Seq() => unreachable(debug(tree, tree.show[Structure]))
      }
    }
  }

  implicit class XtensionSemanticTermRefDefn(tree: Term.Ref) {
    @hosted def defns: Seq[Member.Term] = (tree: Ref).defns.map(_.require[Member.Term])
    @hosted def defn: Member.Term = (tree: Ref).defn.require[Member.Term]
  }

  // NOTE: the types here are intentionally just Member, not Member.Type
  // because Type.Refs can refer to both type members (obviously) and term members (singleton types)
  implicit class XtensionSemanticTypeRefDefn(tree: Type.Ref) {
    @hosted def defns: Seq[Member] = (tree: Ref).defns
    @hosted def defn: Member = (tree: Ref).defn
  }

  // ===========================
  // PART 5: TYPES
  // ===========================

  implicit class XtensionSemanticType(tree: Type) {
    @hosted def <:<(other: Type): Boolean = implicitly[SemanticContext].isSubtype(tree, other)
    @hosted def =:=(other: Type): Boolean = (tree =:= other) && (other =:= tree)<commit_msg>fixes a typo in the implementation of Type.=:=<commit_after>package scala.meta
package semantic

import org.scalameta.adt._
import org.scalameta.annotations._
import org.scalameta.invariants._
import org.scalameta.unreachable
import scala.language.experimental.macros
import scala.{Seq => _}
import scala.annotation.compileTimeOnly
import scala.collection.immutable.Seq
import scala.reflect.{ClassTag, classTag}
import scala.meta.artifacts._
import scala.meta.prettyprinters._
import scala.meta.internal.{ast => impl} // necessary only to implement APIs, not to define them
import scala.meta.internal.{semantic => s} // necessary only to implement APIs, not to define them
import scala.meta.internal.{equality => e} // necessary only to implement APIs, not to define them
import scala.meta.internal.prettyprinters.Summary // necessary only to implement APIs, not to define them
import scala.meta.internal.ast.Helpers._ // necessary only to implement APIs, not to define them
import scala.reflect.runtime.{universe => ru} // necessary only for a very hacky approximation of hygiene

private[meta] trait Api {
  // ===========================
  // PART 1: PRETTYPRINTING
  // ===========================
  implicit def showSemantics[T <: Tree](implicit c: SemanticContext): Semantics[T] = scala.meta.internal.prettyprinters.TreeSemantics.apply[T](c)

  // ===========================
  // PART 2: EQUALITY
  // ===========================

  implicit class XtensionTypecheckingEquality[T1 <: Tree](tree1: T1) {
    @hosted def =:=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = e.Typechecking.equals(tree1, tree2)
    @hosted def =!=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = !e.Typechecking.equals(tree1, tree2)
  }

  implicit class XtensionNormalizingEquality[T1 <: Tree](tree1: T1) {
    @hosted def =~=[T2 <: Tree](tree2: T2)(implicit ev: e.AllowEquality[T1, T2]): Boolean = e.Normalizing.equals(tree1, tree2)
    // TODO: what would be the symbol to express negation of =~=?
  }

  // ===========================
  // PART 3: CONFIGURATION
  // ===========================

  @hosted def dialect: Dialect = implicitly[SemanticContext].dialect

  @hosted def domain: Domain = implicitly[SemanticContext].domain

  implicit class XtensionDomainLikeContext(c: SemanticContext) {
    def sources: Seq[Source] = c.domain.sources
    def resources: Seq[Resource] = c.domain.resources
  }

  // ===========================
  // PART 4: ATTRIBUTES
  // ===========================

  implicit class XtensionSemanticTermDesugar(tree: Term) {
    @hosted def desugar: Term = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term]
      ttree.expansion match {
        case s.Expansion.Zero => unreachable
        case s.Expansion.Identity => ttree
        case s.Expansion.Desugaring(desugaring) => desugaring
      }
    }
  }

  implicit class XtensionSemanticTermTpe(tree: Term) {
    @hosted def tpe: Type = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term]
      ttree.typing match {
        case s.Typing.Zero => unreachable
        case s.Typing.Recursive => impl.Type.Singleton(tree.require[impl.Term.Ref]).setTypechecked
        case s.Typing.Nonrecursive(tpe) => tpe.require[impl.Type]
      }
    }
  }

  implicit class XtensionSemanticMemberTpe(tree: Member) {
    @hosted private def SeqRef: impl.Type.Name = {
      val sScala = s.Symbol.Global(s.Symbol.RootPackage, "scala", s.Signature.Term)
      val sCollection = s.Symbol.Global(sScala, "collection", s.Signature.Term)
      val sSeq = s.Symbol.Global(sCollection, "Seq", s.Signature.Type)
      impl.Type.Name("Seq").withAttrs(s.Denotation.Single(s.Prefix.Zero, sSeq)).setTypechecked
    }
    @hosted private def paramType(tree: impl.Term.Param): Type = {
      val ttree = implicitly[SemanticContext].typecheck(tree).require[impl.Term.Param]
      ttree.typing match {
        case s.Typing.Zero => unreachable
        case s.Typing.Recursive => unreachable
        case s.Typing.Nonrecursive(impl.Type.Arg.ByName(tpe)) => impl.Type.Apply(SeqRef, List(tpe)).setTypechecked
        case s.Typing.Nonrecursive(impl.Type.Arg.Repeated(tpe)) => tpe
        case s.Typing.Nonrecursive(tpe: impl.Type) => tpe
      }
    }
    @hosted private def methodType(tparams: Seq[Type.Param], paramss: Seq[Seq[Term.Param]], ret: Type): Type = {
      if (tparams.nonEmpty) {
        val monoret = methodType(Nil, paramss, ret.require[impl.Type]).require[impl.Type]
        impl.Type.Lambda(tparams.require[Seq[impl.Type.Param]], monoret).setTypechecked
      } else paramss.foldRight(ret.require[impl.Type])((params, acc) => {
        val paramtypes = params.map(p => paramType(p.require[impl.Term.Param]).require[impl.Type.Arg])
        impl.Type.Function(paramtypes, acc).setTypechecked
      })
    }
    @hosted private def ctorType(owner: Member, paramss: Seq[Seq[Term.Param]]): Type = {
      val tparams = owner.tparams
      val ret = {
        if (tparams.nonEmpty) impl.Type.Apply(owner.tpe.require[impl.Type], tparams.map(_.name.require[impl.Type.Name]))
        else owner.tpe
      }.setTypechecked
      methodType(tparams, paramss, ret)
    }
    @hosted def tpe: Type = tree.require[impl.Member] match {
      case tree: impl.Pat.Var.Term => tree.name.tpe
      case tree: impl.Pat.Var.Type => tree.name
      case tree: impl.Decl.Def => methodType(tree.tparams, tree.paramss, tree.decltpe)
      case tree: impl.Decl.Type => tree.name
      case tree: impl.Defn.Def => methodType(tree.tparams, tree.paramss, tree.decltpe.getOrElse(tree.body.tpe))
      case tree: impl.Defn.Macro => methodType(tree.tparams, tree.paramss, tree.decltpe)
      case tree: impl.Defn.Type => tree.name
      case tree: impl.Defn.Class => tree.name
      case tree: impl.Defn.Trait => tree.name
      case tree: impl.Defn.Object => impl.Type.Singleton(tree.name).setTypechecked
      case       impl.Pkg(name: impl.Term.Name, _) => impl.Type.Singleton(name).setTypechecked
      case       impl.Pkg(impl.Term.Select(_, name: impl.Term.Name), _) => impl.Type.Singleton(name).setTypechecked
      case tree: impl.Pkg.Object => impl.Type.Singleton(tree.name).setTypechecked
      case tree: impl.Term.Param if tree.parent.map(_.isInstanceOf[impl.Template]).getOrElse(false) => ??? // TODO: don't forget to intersect with the owner type
      case tree: impl.Term.Param => paramType(tree)
      case tree: impl.Type.Param => tree.name.require[Type.Name]
      case tree: impl.Ctor.Primary => ctorType(tree.owner.require[Member], tree.paramss)
      case tree: impl.Ctor.Secondary => ctorType(tree.owner.require[Member], tree.paramss)
    }
  }

  implicit class XtensionSemanticRefDefn(tree: Ref) {
    @hosted def defns: Seq[Member] = implicitly[SemanticContext].defns(tree)
    @hosted def defn: Member = {
      defns match {
        case Seq(single) => single
        case Seq(_, _*) => throw new SemanticException(s"multiple definitions found for ${showSummary(tree)}")
        case Seq() => unreachable(debug(tree, tree.show[Structure]))
      }
    }
  }

  implicit class XtensionSemanticTermRefDefn(tree: Term.Ref) {
    @hosted def defns: Seq[Member.Term] = (tree: Ref).defns.map(_.require[Member.Term])
    @hosted def defn: Member.Term = (tree: Ref).defn.require[Member.Term]
  }

  // NOTE: the types here are intentionally just Member, not Member.Type
  // because Type.Refs can refer to both type members (obviously) and term members (singleton types)
  implicit class XtensionSemanticTypeRefDefn(tree: Type.Ref) {
    @hosted def defns: Seq[Member] = (tree: Ref).defns
    @hosted def defn: Member = (tree: Ref).defn
  }

  // ===========================
  // PART 5: TYPES
  // ===========================

  implicit class XtensionSemanticType(tree: Type) {
    @hosted def <:<(other: Type): Boolean = implicitly[SemanticContext].isSubtype(tree, other)
    @hosted def =:=(other: Type): Boolean = (tree <:< other) && (other <:< tree)
{'fraction_non_alphanumeric': 0.1609008445417579, 'fraction_numerical': 0.004003753518923991, 'mean_word_length': 3.7059169855755076, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5628132', 'n_tokens_mistral': 5274, 'n_tokens_neox': 5206, 'n_words': 1108}