Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Backport changes for presentation compiler #20345

Merged
merged 1 commit into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions presentation-compiler/src/main/dotty/tools/pc/HoverProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.util as ju
import scala.meta.internal.metals.Report
import scala.meta.internal.metals.ReportContext
import scala.meta.internal.pc.ScalaHover
import scala.meta.pc.ContentType
import scala.meta.pc.HoverSignature
import scala.meta.pc.OffsetParams
import scala.meta.pc.SymbolSearch
Expand All @@ -30,7 +31,8 @@ object HoverProvider:
def hover(
params: OffsetParams,
driver: InteractiveDriver,
search: SymbolSearch
search: SymbolSearch,
contentType: ContentType
)(implicit reportContext: ReportContext): ju.Optional[HoverSignature] =
val uri = params.uri().nn
val text = params.text().nn
Expand Down Expand Up @@ -101,10 +103,10 @@ object HoverProvider:
skipCheckOnName
) match
case Nil =>
fallbackToDynamics(path, printer)
fallbackToDynamics(path, printer, contentType)
case (symbol, tpe) :: _
if symbol.name == nme.selectDynamic || symbol.name == nme.applyDynamic =>
fallbackToDynamics(path, printer)
fallbackToDynamics(path, printer, contentType)
case symbolTpes @ ((symbol, tpe) :: _) =>
val exprTpw = tpe.widenTermRefExpr.deepDealias
val hoverString =
Expand All @@ -126,7 +128,7 @@ object HoverProvider:
end hoverString

val docString = symbolTpes
.flatMap(symTpe => search.symbolDocumentation(symTpe._1))
.flatMap(symTpe => search.symbolDocumentation(symTpe._1, contentType))
.map(_.docstring())
.mkString("\n")
printer.expressionType(exprTpw) match
Expand All @@ -144,7 +146,8 @@ object HoverProvider:
symbolSignature = Some(hoverString),
docstring = Some(docString),
forceExpressionType = forceExpressionType,
contextInfo = printer.getUsedRenamesInfo
contextInfo = printer.getUsedRenamesInfo,
contentType = contentType
)
).nn
case _ =>
Expand All @@ -159,7 +162,8 @@ object HoverProvider:

private def fallbackToDynamics(
path: List[Tree],
printer: ShortenedTypePrinter
printer: ShortenedTypePrinter,
contentType: ContentType
)(using Context): ju.Optional[HoverSignature] = path match
case SelectDynamicExtractor(sel, n, name) =>
def findRefinement(tp: Type): Option[HoverSignature] =
Expand All @@ -178,7 +182,8 @@ object HoverProvider:
new ScalaHover(
expressionType = Some(tpeString),
symbolSignature = Some(s"$valOrDef $name$tpeString"),
contextInfo = printer.getUsedRenamesInfo
contextInfo = printer.getUsedRenamesInfo,
contentType = contentType
)
)
case RefinedType(parent, _, _) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class PcInlayHintsProvider(
val source =
SourceFile.virtual(filePath.toString, sourceText)
driver.run(uri, source)
given InlayHintsParams = params

given InferredType.Text = InferredType.Text(text)
given ctx: Context = driver.currentCtx
Expand All @@ -65,7 +66,7 @@ class PcInlayHintsProvider(
tree: Tree,
): InlayHints =
tree match
case ImplicitConversion(symbol, range) if params.implicitConversions() =>
case ImplicitConversion(symbol, range) =>
val adjusted = adjustPos(range)
inlayHints
.add(
Expand All @@ -78,8 +79,7 @@ class PcInlayHintsProvider(
LabelPart(")") :: Nil,
InlayHintKind.Parameter,
)
case ImplicitParameters(symbols, pos, allImplicit)
if params.implicitParameters() =>
case ImplicitParameters(symbols, pos, allImplicit) =>
val labelParts = symbols.map(s => List(labelPart(s, s.decodedName)))
val label =
if allImplicit then labelParts.separated("(using ", ", ", ")")
Expand All @@ -89,22 +89,22 @@ class PcInlayHintsProvider(
label,
InlayHintKind.Parameter,
)
case ValueOf(label, pos) if params.implicitParameters() =>
case ValueOf(label, pos) =>
inlayHints.add(
adjustPos(pos).toLsp,
LabelPart("(") :: LabelPart(label) :: List(LabelPart(")")),
InlayHintKind.Parameter,
)
case TypeParameters(tpes, pos, sel)
if params.typeParameters() && !syntheticTupleApply(sel) =>
if !syntheticTupleApply(sel) =>
val label = tpes.map(toLabelParts(_, pos)).separated("[", ", ", "]")
inlayHints.add(
adjustPos(pos).endPos.toLsp,
label,
InlayHintKind.Type,
)
case InferredType(tpe, pos, defTree)
if params.inferredTypes() && !isErrorTpe(tpe) =>
if !isErrorTpe(tpe) =>
val adjustedPos = adjustPos(pos).endPos
if inlayHints.containsDef(adjustedPos.start) then inlayHints
else
Expand Down Expand Up @@ -191,14 +191,16 @@ class PcInlayHintsProvider(
end PcInlayHintsProvider

object ImplicitConversion:
def unapply(tree: Tree)(using Context) =
tree match
case Apply(fun: Ident, args) if isSynthetic(fun) =>
implicitConversion(fun, args)
case Apply(Select(fun, name), args)
if name == nme.apply && isSynthetic(fun) =>
implicitConversion(fun, args)
case _ => None
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
if (params.implicitConversions()) {
tree match
case Apply(fun: Ident, args) if isSynthetic(fun) =>
implicitConversion(fun, args)
case Apply(Select(fun, name), args)
if name == nme.apply && isSynthetic(fun) =>
implicitConversion(fun, args)
case _ => None
} else None
private def isSynthetic(tree: Tree)(using Context) =
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit)

Expand All @@ -212,52 +214,64 @@ object ImplicitConversion:
end ImplicitConversion

object ImplicitParameters:
def unapply(tree: Tree)(using Context) =
tree match
case Apply(fun, args)
if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent =>
val (implicitArgs, providedArgs) = args.partition(isSyntheticArg)
val allImplicit = providedArgs.isEmpty || providedArgs.forall {
case Ident(name) => name == nme.MISSING
case _ => false
}
val pos = implicitArgs.head.sourcePos
Some(implicitArgs.map(_.symbol), pos, allImplicit)
case _ => None
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
if (params.implicitParameters()) {
tree match
case Apply(fun, args)
if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent =>
val (implicitArgs, providedArgs) = args.partition(isSyntheticArg)
val allImplicit = providedArgs.isEmpty || providedArgs.forall {
case Ident(name) => name == nme.MISSING
case _ => false
}
val pos = implicitArgs.head.sourcePos
Some(implicitArgs.map(_.symbol), pos, allImplicit)
case _ => None
} else None

private def isSyntheticArg(tree: Tree)(using Context) = tree match
case tree: Ident =>
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit)
tree.span.isSynthetic && tree.symbol.isOneOf(Flags.GivenOrImplicit) &&
!isQuotes(tree)
case _ => false

// Decorations for Quotes are rarely useful
private def isQuotes(tree: Tree)(using Context) =
tree.tpe.typeSymbol == defn.QuotesClass

end ImplicitParameters

object ValueOf:
def unapply(tree: Tree)(using Context) =
tree match
case Apply(ta @ TypeApply(fun, _), _)
if fun.span.isSynthetic && isValueOf(fun) =>
Some(
"new " + tpnme.valueOf.decoded.capitalize + "(...)",
fun.sourcePos,
)
case _ => None
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
if (params.implicitParameters()) {
tree match
case Apply(ta @ TypeApply(fun, _), _)
if fun.span.isSynthetic && isValueOf(fun) =>
Some(
"new " + tpnme.valueOf.decoded.capitalize + "(...)",
fun.sourcePos,
)
case _ => None
} else None
private def isValueOf(tree: Tree)(using Context) =
val symbol = tree.symbol.maybeOwner
symbol.name.decoded == tpnme.valueOf.decoded.capitalize
end ValueOf

object TypeParameters:
def unapply(tree: Tree)(using Context) =
tree match
case TypeApply(sel: Select, _) if sel.isForComprehensionMethod => None
case TypeApply(fun, args) if inferredTypeArgs(args) =>
val pos = fun match
case sel: Select if sel.isInfix =>
sel.sourcePos.withEnd(sel.nameSpan.end)
case _ => fun.sourcePos
val tpes = args.map(_.typeOpt.stripTypeVar.widen.finalResultType)
Some((tpes, pos.endPos, fun))
case _ => None
def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context) =
if (params.typeParameters()) {
tree match
case TypeApply(sel: Select, _)
if sel.isForComprehensionMethod || sel.isInfix ||
sel.symbol.name == nme.unapply =>
None
case TypeApply(fun, args) if inferredTypeArgs(args) =>
val tpes = args.map(_.tpe.stripTypeVar.widen.finalResultType)
Some((tpes, fun.sourcePos.endPos, fun))
case _ => None
} else None

private def inferredTypeArgs(args: List[Tree]): Boolean =
args.forall {
case tt: TypeTree if tt.span.exists && !tt.span.isZeroExtent => true
Expand All @@ -270,29 +284,35 @@ object InferredType:
object Text:
def apply(text: Array[Char]): Text = text

def unapply(tree: Tree)(using text: Text, cxt: Context) =
tree match
case vd @ ValDef(_, tpe, _)
if isValidSpan(tpe.span, vd.nameSpan) &&
!vd.symbol.is(Flags.Enum) &&
!isValDefBind(text, vd) =>
if vd.symbol == vd.symbol.sourceSymbol then
Some(tpe.typeOpt, tpe.sourcePos.withSpan(vd.nameSpan), vd)
else None
case vd @ DefDef(_, _, tpe, _)
if isValidSpan(tpe.span, vd.nameSpan) &&
tpe.span.start >= vd.nameSpan.end &&
!vd.symbol.isConstructor &&
!vd.symbol.is(Flags.Mutable) =>
if vd.symbol == vd.symbol.sourceSymbol then
Some(tpe.typeOpt, tpe.sourcePos, vd)
else None
case bd @ Bind(
name,
Ident(nme.WILDCARD),
) =>
Some(bd.symbol.info, bd.namePos, bd)
case _ => None
def unapply(tree: Tree)(using params: InlayHintsParams, text: Text, ctx: Context) =
if (params.inferredTypes()) {
tree match
case vd @ ValDef(_, tpe, _)
if isValidSpan(tpe.span, vd.nameSpan) &&
!vd.symbol.is(Flags.Enum) &&
(isNotInUnapply(vd) || params.hintsInPatternMatch()) &&
!isValDefBind(text, vd) =>
if vd.symbol == vd.symbol.sourceSymbol then
Some(tpe.tpe, tpe.sourcePos.withSpan(vd.nameSpan), vd)
else None
case vd @ DefDef(_, _, tpe, _)
if isValidSpan(tpe.span, vd.nameSpan) &&
tpe.span.start >= vd.nameSpan.end &&
!vd.symbol.isConstructor &&
!vd.symbol.is(Flags.Mutable) =>
if vd.symbol == vd.symbol.sourceSymbol then
Some(tpe.tpe, tpe.sourcePos, vd)
else None
case bd @ Bind(
name,
Ident(nme.WILDCARD),
) if !bd.span.isZeroExtent && bd.symbol.isTerm && params.hintsInPatternMatch() =>
Some(bd.symbol.info, bd.namePos, bd)
case _ => None
} else None

private def isNotInUnapply(vd: ValDef)(using Context) =
vd.rhs.span.exists && vd.rhs.span.start > vd.nameSpan.end

private def isValidSpan(tpeSpan: Span, nameSpan: Span): Boolean =
tpeSpan.isZeroExtent &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ case class ScalaPresentationCompiler(
params.token()
) { access =>
val driver = access.compiler()
HoverProvider.hover(params, driver, search)
HoverProvider.hover(params, driver, search, config.hoverContentType())
}
end hover

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import dotty.tools.dotc.core.Symbols.NoSymbol
import dotty.tools.dotc.core.Symbols.Symbol
import dotty.tools.dotc.core.Types.AndType
import dotty.tools.dotc.core.Types.ClassInfo
import dotty.tools.dotc.core.Types.NoType
import dotty.tools.dotc.core.Types.OrType
import dotty.tools.dotc.core.Types.Type
import dotty.tools.dotc.core.Types.TypeRef
Expand Down Expand Up @@ -94,7 +95,7 @@ object CaseKeywordCompletion:
Some(sel.tpe.widen.deepDealias)

selTpe
.map { selTpe =>
.collect { case selTpe if selTpe != NoType =>
val selectorSym = selTpe.typeSymbol
// Special handle case when selector is a tuple or `FunctionN`.
if definitions.isTupleClass(selectorSym) || definitions.isFunctionClass(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import scala.annotation.tailrec
import scala.meta.internal.jdk.CollectionConverters.*
import scala.meta.internal.mtags.CommonMtagsEnrichments
import scala.meta.internal.mtags.KeywordWrapper
import scala.meta.pc.ContentType
import scala.meta.pc.OffsetParams
import scala.meta.pc.RangeParams
import scala.meta.pc.SymbolDocumentation
Expand Down Expand Up @@ -260,7 +261,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
}

extension (search: SymbolSearch)
def symbolDocumentation(symbol: Symbol)(using
def symbolDocumentation(symbol: Symbol, contentType: ContentType = ContentType.MARKDOWN)(using
Context
): Option[SymbolDocumentation] =
def toSemanticdbSymbol(symbol: Symbol) =
Expand All @@ -280,6 +281,7 @@ object InteractiveEnrichments extends CommonMtagsEnrichments:
val documentation = search.documentation(
sym,
() => parentSymbols.iterator.map(toSemanticdbSymbol).toList.asJava,
contentType,
)
documentation.nn.toScala
end symbolDocumentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class BaseInlayHintsSuite extends BasePCSuite {
base: String,
expected: String,
kind: Option[Int] = None,
hintsInPatternMatch: Boolean = false
): Unit =
def pkgWrap(text: String) =
if (text.contains("package")) text
Expand All @@ -35,7 +36,8 @@ class BaseInlayHintsSuite extends BasePCSuite {
true,
true,
true,
true
true,
hintsInPatternMatch
)

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

assertNoDiff(
pkgWrap(expected),
obtained,
pkgWrap(expected)
)

}
Loading
Loading