Skip to content

Commit 1cdf99f

Browse files
authored
chore: Backport changes for presentation compiler (#20345)
Changes from: - scalameta/metals#6225 - scalameta/metals#6236 - scalameta/metals#6241 - scalameta/metals#6303 - scalameta/metals#6308
1 parent 6af2bcf commit 1cdf99f

File tree

11 files changed

+409
-93
lines changed

11 files changed

+409
-93
lines changed

presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala

+12-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.util as ju
55
import scala.meta.internal.metals.Report
66
import scala.meta.internal.metals.ReportContext
77
import scala.meta.internal.pc.ScalaHover
8+
import scala.meta.pc.ContentType
89
import scala.meta.pc.HoverSignature
910
import scala.meta.pc.OffsetParams
1011
import scala.meta.pc.SymbolSearch
@@ -30,7 +31,8 @@ object HoverProvider:
3031
def hover(
3132
params: OffsetParams,
3233
driver: InteractiveDriver,
33-
search: SymbolSearch
34+
search: SymbolSearch,
35+
contentType: ContentType
3436
)(implicit reportContext: ReportContext): ju.Optional[HoverSignature] =
3537
val uri = params.uri().nn
3638
val text = params.text().nn
@@ -101,10 +103,10 @@ object HoverProvider:
101103
skipCheckOnName
102104
) match
103105
case Nil =>
104-
fallbackToDynamics(path, printer)
106+
fallbackToDynamics(path, printer, contentType)
105107
case (symbol, tpe) :: _
106108
if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic =>
107-
fallbackToDynamics(path, printer)
109+
fallbackToDynamics(path, printer, contentType)
108110
case symbolTpes @ ((symbol, tpe) :: _) =>
109111
val exprTpw = tpe.widenTermRefExpr.deepDealias
110112
val hoverString =
@@ -126,7 +128,7 @@ object HoverProvider:
126128
end hoverString
127129

128130
val docString = symbolTpes
129-
.flatMap(symTpe => search.symbolDocumentation(symTpe._1))
131+
.flatMap(symTpe => search.symbolDocumentation(symTpe._1, contentType))
130132
.map(_.docstring())
131133
.mkString("\n")
132134
printer.expressionType(exprTpw) match
@@ -144,7 +146,8 @@ object HoverProvider:
144146
symbolSignature = Some(hoverString),
145147
docstring = Some(docString),
146148
forceExpressionType = forceExpressionType,
147-
contextInfo = printer.getUsedRenamesInfo
149+
contextInfo = printer.getUsedRenamesInfo,
150+
contentType = contentType
148151
)
149152
).nn
150153
case _ =>
@@ -159,7 +162,8 @@ object HoverProvider:
159162

160163
private def fallbackToDynamics(
161164
path: List[Tree],
162-
printer: ShortenedTypePrinter
165+
printer: ShortenedTypePrinter,
166+
contentType: ContentType
163167
)(using Context): ju.Optional[HoverSignature] = path match
164168
case SelectDynamicExtractor(sel, n, name) =>
165169
def findRefinement(tp: Type): Option[HoverSignature] =
@@ -178,7 +182,8 @@ object HoverProvider:
178182
new ScalaHover(
179183
expressionType = Some(tpeString),
180184
symbolSignature = Some(s"$valOrDef $name$tpeString"),
181-
contextInfo = printer.getUsedRenamesInfo
185+
contextInfo = printer.getUsedRenamesInfo,
186+
contentType = contentType
182187
)
183188
)
184189
case RefinedType(parent, _, _) =>

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

+90-70
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class PcInlayHintsProvider(
4242
val source =
4343
SourceFile.virtual(filePath.toString, sourceText)
4444
driver.run(uri, source)
45+
given InlayHintsParams = params
4546

4647
given InferredType.Text = InferredType.Text(text)
4748
given ctx: Context = driver.currentCtx
@@ -65,7 +66,7 @@ class PcInlayHintsProvider(
6566
tree: Tree,
6667
): InlayHints =
6768
tree match
68-
case ImplicitConversion(symbol, range) if params.implicitConversions() =>
69+
case ImplicitConversion(symbol, range) =>
6970
val adjusted = adjustPos(range)
7071
inlayHints
7172
.add(
@@ -78,8 +79,7 @@ class PcInlayHintsProvider(
7879
LabelPart(")") :: Nil,
7980
InlayHintKind.Parameter,
8081
)
81-
case ImplicitParameters(symbols, pos, allImplicit)
82-
if params.implicitParameters() =>
82+
case ImplicitParameters(symbols, pos, allImplicit) =>
8383
val labelParts = symbols.map(s => List(labelPart(s, s.decodedName)))
8484
val label =
8585
if allImplicit then labelParts.separated("(using ", ", ", ")")
@@ -89,22 +89,22 @@ class PcInlayHintsProvider(
8989
label,
9090
InlayHintKind.Parameter,
9191
)
92-
case ValueOf(label, pos) if params.implicitParameters() =>
92+
case ValueOf(label, pos) =>
9393
inlayHints.add(
9494
adjustPos(pos).toLsp,
9595
LabelPart("(") :: LabelPart(label) :: List(LabelPart(")")),
9696
InlayHintKind.Parameter,
9797
)
9898
case TypeParameters(tpes, pos, sel)
99-
if params.typeParameters() && !syntheticTupleApply(sel) =>
99+
if !syntheticTupleApply(sel) =>
100100
val label = tpes.map(toLabelParts(_, pos)).separated("[", ", ", "]")
101101
inlayHints.add(
102102
adjustPos(pos).endPos.toLsp,
103103
label,
104104
InlayHintKind.Type,
105105
)
106106
case InferredType(tpe, pos, defTree)
107-
if params.inferredTypes() && !isErrorTpe(tpe) =>
107+
if !isErrorTpe(tpe) =>
108108
val adjustedPos = adjustPos(pos).endPos
109109
if inlayHints.containsDef(adjustedPos.start) then inlayHints
110110
else
@@ -191,14 +191,16 @@ class PcInlayHintsProvider(
191191
end PcInlayHintsProvider
192192

193193
object ImplicitConversion:
194-
def unapply(tree: Tree)(using Context) =
195-
tree match
196-
case Apply(fun: Ident, args) if isSynthetic(fun) =>
197-
implicitConversion(fun, args)
198-
case Apply(Select(fun, name), args)
199-
if name == nme.apply && isSynthetic(fun) =>
200-
implicitConversion(fun, args)
201-
case _ => None
194+
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
195+
if (params.implicitConversions()) {
196+
tree match
197+
case Apply(fun: Ident, args) if isSynthetic(fun) =>
198+
implicitConversion(fun, args)
199+
case Apply(Select(fun, name), args)
200+
if name == nme.apply && isSynthetic(fun) =>
201+
implicitConversion(fun, args)
202+
case _ => None
203+
} else None
202204
private def isSynthetic(tree: Tree)(using Context) =
203205
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit)
204206

@@ -212,52 +214,64 @@ object ImplicitConversion:
212214
end ImplicitConversion
213215

214216
object ImplicitParameters:
215-
def unapply(tree: Tree)(using Context) =
216-
tree match
217-
case Apply(fun, args)
218-
if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent =>
219-
val (implicitArgs, providedArgs) = args.partition(isSyntheticArg)
220-
val allImplicit = providedArgs.isEmpty || providedArgs.forall {
221-
case Ident(name) => name == nme.MISSING
222-
case _ => false
223-
}
224-
val pos = implicitArgs.head.sourcePos
225-
Some(implicitArgs.map(_.symbol), pos, allImplicit)
226-
case _ => None
217+
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
218+
if (params.implicitParameters()) {
219+
tree match
220+
case Apply(fun, args)
221+
if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent =>
222+
val (implicitArgs, providedArgs) = args.partition(isSyntheticArg)
223+
val allImplicit = providedArgs.isEmpty || providedArgs.forall {
224+
case Ident(name) => name == nme.MISSING
225+
case _ => false
226+
}
227+
val pos = implicitArgs.head.sourcePos
228+
Some(implicitArgs.map(_.symbol), pos, allImplicit)
229+
case _ => None
230+
} else None
227231

228232
private def isSyntheticArg(tree: Tree)(using Context) = tree match
229233
case tree: Ident =>
230-
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit)
234+
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit) &&
235+
!isQuotes(tree)
231236
case _ => false
237+
238+
// Decorations for Quotes are rarely useful
239+
private def isQuotes(tree: Tree)(using Context) =
240+
tree.tpe.typeSymbol == defn.QuotesClass
241+
232242
end ImplicitParameters
233243

234244
object ValueOf:
235-
def unapply(tree: Tree)(using Context) =
236-
tree match
237-
case Apply(ta @ TypeApply(fun, _), _)
238-
if fun.span.isSynthetic && isValueOf(fun) =>
239-
Some(
240-
"new " + tpnme.valueOf.decoded.capitalize + "(...)",
241-
fun.sourcePos,
242-
)
243-
case _ => None
245+
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
246+
if (params.implicitParameters()) {
247+
tree match
248+
case Apply(ta @ TypeApply(fun, _), _)
249+
if fun.span.isSynthetic && isValueOf(fun) =>
250+
Some(
251+
"new " + tpnme.valueOf.decoded.capitalize + "(...)",
252+
fun.sourcePos,
253+
)
254+
case _ => None
255+
} else None
244256
private def isValueOf(tree: Tree)(using Context) =
245257
val symbol = tree.symbol.maybeOwner
246258
symbol.name.decoded == tpnme.valueOf.decoded.capitalize
247259
end ValueOf
248260

249261
object TypeParameters:
250-
def unapply(tree: Tree)(using Context) =
251-
tree match
252-
case TypeApply(sel: Select, _) if sel.isForComprehensionMethod => None
253-
case TypeApply(fun, args) if inferredTypeArgs(args) =>
254-
val pos = fun match
255-
case sel: Select if sel.isInfix =>
256-
sel.sourcePos.withEnd(sel.nameSpan.end)
257-
case _ => fun.sourcePos
258-
val tpes = args.map(_.typeOpt.stripTypeVar.widen.finalResultType)
259-
Some((tpes, pos.endPos, fun))
260-
case _ => None
262+
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
263+
if (params.typeParameters()) {
264+
tree match
265+
case TypeApply(sel: Select, _)
266+
if sel.isForComprehensionMethod || sel.isInfix ||
267+
sel.symbol.name == nme.unapply =>
268+
None
269+
case TypeApply(fun, args) if inferredTypeArgs(args) =>
270+
val tpes = args.map(_.tpe.stripTypeVar.widen.finalResultType)
271+
Some((tpes, fun.sourcePos.endPos, fun))
272+
case _ => None
273+
} else None
274+
261275
private def inferredTypeArgs(args: List[Tree]): Boolean =
262276
args.forall {
263277
case tt: TypeTree if tt.span.exists && !tt.span.isZeroExtent => true
@@ -270,29 +284,35 @@ object InferredType:
270284
object Text:
271285
def apply(text: Array[Char]): Text = text
272286

273-
def unapply(tree: Tree)(using text: Text, cxt: Context) =
274-
tree match
275-
case vd @ ValDef(_, tpe, _)
276-
if isValidSpan(tpe.span, vd.nameSpan) &&
277-
!vd.symbol.is(Flags.Enum) &&
278-
!isValDefBind(text, vd) =>
279-
if vd.symbol == vd.symbol.sourceSymbol then
280-
Some(tpe.typeOpt, tpe.sourcePos.withSpan(vd.nameSpan), vd)
281-
else None
282-
case vd @ DefDef(_, _, tpe, _)
283-
if isValidSpan(tpe.span, vd.nameSpan) &&
284-
tpe.span.start >= vd.nameSpan.end &&
285-
!vd.symbol.isConstructor &&
286-
!vd.symbol.is(Flags.Mutable) =>
287-
if vd.symbol == vd.symbol.sourceSymbol then
288-
Some(tpe.typeOpt, tpe.sourcePos, vd)
289-
else None
290-
case bd @ Bind(
291-
name,
292-
Ident(nme.WILDCARD),
293-
) =>
294-
Some(bd.symbol.info, bd.namePos, bd)
295-
case _ => None
287+
def unapply(tree: Tree)(using params: InlayHintsParams, text: Text, ctx: Context) =
288+
if (params.inferredTypes()) {
289+
tree match
290+
case vd @ ValDef(_, tpe, _)
291+
if isValidSpan(tpe.span, vd.nameSpan) &&
292+
!vd.symbol.is(Flags.Enum) &&
293+
(isNotInUnapply(vd) || params.hintsInPatternMatch()) &&
294+
!isValDefBind(text, vd) =>
295+
if vd.symbol == vd.symbol.sourceSymbol then
296+
Some(tpe.tpe, tpe.sourcePos.withSpan(vd.nameSpan), vd)
297+
else None
298+
case vd @ DefDef(_, _, tpe, _)
299+
if isValidSpan(tpe.span, vd.nameSpan) &&
300+
tpe.span.start >= vd.nameSpan.end &&
301+
!vd.symbol.isConstructor &&
302+
!vd.symbol.is(Flags.Mutable) =>
303+
if vd.symbol == vd.symbol.sourceSymbol then
304+
Some(tpe.tpe, tpe.sourcePos, vd)
305+
else None
306+
case bd @ Bind(
307+
name,
308+
Ident(nme.WILDCARD),
309+
) if !bd.span.isZeroExtent && bd.symbol.isTerm && params.hintsInPatternMatch() =>
310+
Some(bd.symbol.info, bd.namePos, bd)
311+
case _ => None
312+
} else None
313+
314+
private def isNotInUnapply(vd: ValDef)(using Context) =
315+
vd.rhs.span.exists && vd.rhs.span.start > vd.nameSpan.end
296316

297317
private def isValidSpan(tpeSpan: Span, nameSpan: Span): Boolean =
298318
tpeSpan.isZeroExtent &&

presentation-compiler/src/main/dotty/tools/pc/ScalaPresentationCompiler.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ case class ScalaPresentationCompiler(
360360
params.token()
361361
) { access =>
362362
val driver = access.compiler()
363-
HoverProvider.hover(params, driver, search)
363+
HoverProvider.hover(params, driver, search, config.hoverContentType())
364364
}
365365
end hover
366366

presentation-compiler/src/main/dotty/tools/pc/completions/MatchCaseCompletions.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import dotty.tools.dotc.core.Symbols.NoSymbol
2323
import dotty.tools.dotc.core.Symbols.Symbol
2424
import dotty.tools.dotc.core.Types.AndType
2525
import dotty.tools.dotc.core.Types.ClassInfo
26+
import dotty.tools.dotc.core.Types.NoType
2627
import dotty.tools.dotc.core.Types.OrType
2728
import dotty.tools.dotc.core.Types.Type
2829
import dotty.tools.dotc.core.Types.TypeRef
@@ -94,7 +95,7 @@ object CaseKeywordCompletion:
9495
Some(sel.tpe.widen.deepDealias)
9596

9697
selTpe
97-
.map { selTpe =>
98+
.collect { case selTpe if selTpe != NoType =>
9899
val selectorSym = selTpe.typeSymbol
99100
// Special handle case when selector is a tuple or `FunctionN`.
100101
if definitions.isTupleClass(selectorSym) || definitions.isFunctionClass(

presentation-compiler/src/main/dotty/tools/pc/utils/InteractiveEnrichments.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import scala.annotation.tailrec
44
import scala.meta.internal.jdk.CollectionConverters.*
55
import scala.meta.internal.mtags.CommonMtagsEnrichments
66
import scala.meta.internal.mtags.KeywordWrapper
7+
import scala.meta.pc.ContentType
78
import scala.meta.pc.OffsetParams
89
import scala.meta.pc.RangeParams
910
import scala.meta.pc.SymbolDocumentation
@@ -260,7 +261,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
260261
}
261262

262263
extension (search: SymbolSearch)
263-
def symbolDocumentation(symbol: Symbol)(using
264+
def symbolDocumentation(symbol: Symbol, contentType: ContentType = ContentType.MARKDOWN)(using
264265
Context
265266
): Option[SymbolDocumentation] =
266267
def toSemanticdbSymbol(symbol: Symbol) =
@@ -280,6 +281,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
280281
val documentation = search.documentation(
281282
sym,
282283
() => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava,
284+
contentType,
283285
)
284286
documentation.nn.toScala
285287
end symbolDocumentation

presentation-compiler/test/dotty/tools/pc/base/BaseInlayHintsSuite.scala

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class BaseInlayHintsSuite extends BasePCSuite {
1818
base: String,
1919
expected: String,
2020
kind: Option[Int] = None,
21+
hintsInPatternMatch: Boolean = false
2122
): Unit =
2223
def pkgWrap(text: String) =
2324
if (text.contains("package")) text
@@ -35,7 +36,8 @@ class BaseInlayHintsSuite extends BasePCSuite {
3536
true,
3637
true,
3738
true,
38-
true
39+
true,
40+
hintsInPatternMatch
3941
)
4042

4143
val inlayHints = presentationCompiler
@@ -49,8 +51,8 @@ class BaseInlayHintsSuite extends BasePCSuite {
4951
val obtained = TestInlayHints.applyInlayHints(withPkg, inlayHints)
5052

5153
assertNoDiff(
54+
pkgWrap(expected),
5255
obtained,
53-
pkgWrap(expected)
5456
)
5557

5658
}

0 commit comments

Comments
 (0)