diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala index 1df12a28b1..698576e4c0 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala @@ -988,7 +988,10 @@ class FormatOps( )(implicit style: ScalafmtConfig): Boolean = formatToken.right.is[soft.ImplicitOrUsing] && style.newlines.notBeforeImplicitParamListModifier && - opensImplicitParamList(formatToken).isDefined + hasImplicitParamList(formatToken.meta.rightOwner) + + val ImplicitUsingOnLeft = + new ExtractFromMeta(ft => getImplicitParamList(ft.meta.leftOwner)) def isSingleIdentifierAnnotation(tok: FormatToken): Boolean = { val toMatch = if (tok.right.is[T.RightParen]) { @@ -1288,7 +1291,7 @@ class FormatOps( } else { val rightIsImplicit = r.is[soft.ImplicitOrUsing] val opensImplicit = rightIsImplicit && - opensImplicitParamList(ft).exists(_.lengthCompare(1) > 0) + getImplicitParamList(ft.meta.rightOwner).exists(_.lengthCompare(1) > 0) val nlOnly = if (rightIsImplicit) style.newlines.forceBeforeImplicitParamListModifier @@ -1429,24 +1432,6 @@ class FormatOps( throw UnexpectedTree[Member.SyntaxValuesClause](t) } - def opensImplicitParamList(ft: FormatToken): Option[Seq[Tree]] = - ft.meta.leftOwner match { - case Term.ArgClause(v, _: Some[_]) => Some(v) - case Term.ParamClause(v, Some(mod)) if (mod match { - case _: Mod.Implicit => v.forall(noExplicitImplicit) - case _ => true - }) => - Some(v) - case _ => None - } - - /** Works for `using` as well */ - def opensImplicitParamList(ft: FormatToken, args: Seq[Tree]): Boolean = - ft.right.is[T.KwImplicit] && args.forall { - case t: Term.Param => noExplicitImplicit(t) - case _ => true - } || ft.right.is[soft.KwUsing] - @tailrec final def findPrevSelectAndApply( tree: Tree, @@ -1888,16 +1873,6 @@ class FormatOps( }) && isEnclosedInParens(body) } - // For using to be the soft kw it also has to be preceded by paren - def isRightImplicitOrUsingSoftKw( - ft: FormatToken, - soft: SoftKeywordClasses - ): Boolean = ft.left match { - case _: T.KwImplicit => true - case soft.KwUsing() => prevNonCommentBefore(ft).left.is[T.LeftParen] - case _ => false - } - def getMatchDot(tree: Term.Match): Option[FormatToken] = if (dialect.allowMatchAsOperator) { val ft = tokens.tokenAfter(tree.expr) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala index 49c0dba849..3e29db4489 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala @@ -52,7 +52,6 @@ class Router(formatOps: FormatOps) { tokenBefore, getLastNonTrivial, prevNonComment, - prevNonCommentBefore, nextNonComment, prevNonCommentSameLine, nextNonCommentSameLine @@ -1005,7 +1004,7 @@ class Router(formatOps: FormatOps) { // covers using as well val handleImplicit = !tupleSite && ( if (onlyConfigStyle) opensConfigStyleImplicitParamList(formatToken) - else opensImplicitParamList(formatToken, args) + else hasImplicitParamList(rightOwner) ) val noSplitMod = @@ -2412,24 +2411,19 @@ class Router(formatOps: FormatOps) { case _ => Seq(baseSplit) } - case FormatToken(soft.ImplicitOrUsing(), _, _) + case FormatToken(soft.ImplicitOrUsing(), _, ImplicitUsingOnLeft(params)) if style.binPack.unsafeDefnSite.isNever && - !style.verticalMultiline.atDefnSite && - isRightImplicitOrUsingSoftKw(formatToken, soft) => - opensImplicitParamList(prevNonCommentBefore(formatToken)).fold { - Seq(Split(Space, 0)) - } { params => - val spaceSplit = Split(Space, 0) - .notIf(style.newlines.forceAfterImplicitParamListModifier) - .withPolicy( - SingleLineBlock(params.last.tokens.last), - style.newlines.notPreferAfterImplicitParamListModifier - ) - Seq( - spaceSplit, - Split(Newline, if (spaceSplit.isActive) 1 else 0) + !style.verticalMultiline.atDefnSite => + val spaceSplit = Split(Space, 0) + .notIf(style.newlines.forceAfterImplicitParamListModifier) + .withPolicy( + SingleLineBlock(params.last.tokens.last), + style.newlines.notPreferAfterImplicitParamListModifier ) - } + Seq( + spaceSplit, + Split(Newline, if (spaceSplit.isActive) 1 else 0) + ) case FormatToken(_, r, _) if optionalNewlines(hash(r)) => @tailrec diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala index 09878a157c..8da8143210 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala @@ -636,6 +636,20 @@ object TreeOps { param.mods.forall(noExplicitImplicit(pStart, true)) } + def getImplicitParamList(kwOwner: Tree): Option[Seq[Tree]] = + kwOwner.parent match { + case Some(Term.ArgClause(v, Some(`kwOwner`))) => Some(v) + case Some(Term.ParamClause(v, Some(`kwOwner`))) if (kwOwner match { + case _: Mod.Implicit => v.forall(noExplicitImplicit) + case _ => true + }) => + Some(v) + case _ => None + } + + def hasImplicitParamList(kwOwner: Tree): Boolean = + getImplicitParamList(kwOwner).isDefined + def shouldNotDangleAtDefnSite( tree: Option[Tree], isVerticalMultiline: Boolean