Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit dc14b81

Browse files
Port Inlay hints for name parameters
1 parent 96de70c commit dc14b81

File tree

2 files changed

+211
-88
lines changed

2 files changed

+211
-88
lines changed

‎presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala‎

Lines changed: 85 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import scala.meta.pc.SymbolSearch
1717
import dotty.tools.dotc.ast.tpd.*
1818
import dotty.tools.dotc.core.Contexts.Context
1919
import dotty.tools.dotc.core.Flags
20+
import dotty.tools.dotc.core.NameOps.fieldName
21+
import dotty.tools.dotc.core.Names.Name
2022
import dotty.tools.dotc.core.StdNames.*
2123
import dotty.tools.dotc.core.Symbols.*
2224
import dotty.tools.dotc.core.Types.*
@@ -116,28 +118,44 @@ class PcInlayHintsProvider(
116118
InlayHintKind.Type,
117119
)
118120
.addDefinition(adjustedPos.start)
119-
case ByNameParameters(byNameParams) =>
120-
def adjustByNameParameterPos(pos: SourcePosition): SourcePosition =
121-
val adjusted = adjustPos(pos)
122-
val start = text.indexWhere(!_.isWhitespace, adjusted.start)
123-
val end = text.lastIndexWhere(!_.isWhitespace, adjusted.end - 1)
121+
case Parameters(isInfixFun, args) =>
122+
def isNamedParam(pos: SourcePosition): Boolean =
123+
val start = text.indexWhere(!_.isWhitespace, pos.start)
124+
val end = text.lastIndexWhere(!_.isWhitespace, pos.end - 1)
124125

126+
text.slice(start, end).contains('=')
127+
128+
def isBlockParam(pos: SourcePosition): Boolean =
129+
val start = text.indexWhere(!_.isWhitespace, pos.start)
130+
val end = text.lastIndexWhere(!_.isWhitespace, pos.end - 1)
125131
val startsWithBrace = text.lift(start).contains('{')
126132
val endsWithBrace = text.lift(end).contains('}')
127133

128-
if startsWithBrace && endsWithBrace then
129-
adjusted.withStart(start + 1)
130-
else
131-
adjusted
132-
133-
byNameParams.foldLeft(inlayHints) {
134-
case (ih, pos) =>
135-
val adjusted = adjustByNameParameterPos(pos)
136-
ih.add(
137-
adjusted.startPos.toLsp,
138-
List(LabelPart("=> ")),
139-
InlayHintKind.Parameter
140-
)
134+
startsWithBrace && endsWithBrace
135+
136+
def adjustBlockParamPos(pos: SourcePosition): SourcePosition =
137+
pos.withStart(pos.start + 1)
138+
139+
140+
args.foldLeft(inlayHints) {
141+
case (ih, (name, pos0, isByName)) =>
142+
val pos = adjustPos(pos0)
143+
val isBlock = isBlockParam(pos)
144+
val namedLabel =
145+
if params.namedParameters() && !isInfixFun && !isBlock && !isNamedParam(pos) then s"${name} = " else ""
146+
val byNameLabel =
147+
if params.byNameParameters() && isByName && (!isInfixFun || isBlock) then "=> " else ""
148+
149+
val labelStr = s"${namedLabel}${byNameLabel}"
150+
val hintPos = if isBlock then adjustBlockParamPos(pos) else pos
151+
152+
if labelStr.nonEmpty then
153+
ih.add(
154+
hintPos.startPos.toLsp,
155+
List(LabelPart(labelStr)),
156+
InlayHintKind.Parameter,
157+
)
158+
else ih
141159
}
142160
case _ => inlayHints
143161

@@ -412,27 +430,55 @@ object InferredType:
412430

413431
end InferredType
414432

415-
object ByNameParameters:
416-
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[List[SourcePosition]] =
417-
def shouldSkipSelect(sel: Select) =
418-
isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply
433+
object Parameters:
434+
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[(Boolean, List[(Name, SourcePosition, Boolean)])] =
435+
def shouldSkipFun(fun: Tree)(using Context): Boolean =
436+
fun match
437+
case sel: Select => isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply
438+
case _ => false
439+
440+
def isInfixFun(fun: Tree, args: List[Tree])(using Context): Boolean =
441+
val isInfixSelect = fun match
442+
case Select(sel, _) => sel.isInfix
443+
case _ => false
444+
val source = fun.source
445+
if args.isEmpty then isInfixSelect
446+
else
447+
(!(fun.span.end until args.head.span.start)
448+
.map(source.apply)
449+
.contains('.') && fun.symbol.is(Flags.ExtensionMethod)) || isInfixSelect
450+
451+
def isRealApply(tree: Tree) =
452+
!tree.symbol.isOneOf(Flags.GivenOrImplicit) && !tree.span.isZeroExtent
453+
454+
def getUnderlyingFun(tree: Tree): Tree =
455+
tree match
456+
case Apply(fun, _) => getUnderlyingFun(fun)
457+
case TypeApply(fun, _) => getUnderlyingFun(fun)
458+
case t => t
419459

420-
if (params.byNameParameters()){
460+
if (params.namedParameters() || params.byNameParameters())then
421461
tree match
422-
case Apply(TypeApply(sel: Select, _), _) if shouldSkipSelect(sel) =>
423-
None
424-
case Apply(sel: Select, _) if shouldSkipSelect(sel) =>
425-
None
426-
case Apply(fun, args) =>
427-
val funTp = fun.typeOpt.widenTermRefExpr
428-
val params = funTp.paramInfoss.flatten
429-
Some(
430-
args
431-
.zip(params)
432-
.collect {
433-
case (tree, param) if param.isByName => tree.sourcePos
434-
}
435-
)
462+
case Apply(fun, args) if isRealApply(fun) =>
463+
val underlyingFun = getUnderlyingFun(fun)
464+
if shouldSkipFun(underlyingFun) then
465+
None
466+
else
467+
val funTp = fun.typeOpt.widenTermRefExpr
468+
val paramNames = funTp.paramNamess.flatten
469+
val paramInfos = funTp.paramInfoss.flatten
470+
Some(
471+
// Check if the function is an infix function or the underlying function is an infix function
472+
isInfixFun(fun, args) || underlyingFun.isInfix,
473+
(
474+
args
475+
.zip(paramNames)
476+
.zip(paramInfos)
477+
.collect {
478+
case ((arg, paramName), paramInfo) if !arg.span.isZeroExtent => (paramName.fieldName, arg.sourcePos, paramInfo.isByName)
479+
}
480+
)
481+
)
436482
case _ => None
437-
} else None
438-
end ByNameParameters
483+
else None
484+
end Parameters

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /