Skip to content

Commit f6a7196

Browse files
Attach signature to BindingInfo (#1102)
Unifies the signature information shown in the holes panel between type and term bindings. This is achieved by replacing the `type` and `definition` fields with `signature` and `signatureHtml` fields and implementing a separate pretty-printer for signatures.
1 parent 265c43c commit f6a7196

File tree

3 files changed

+178
-85
lines changed

3 files changed

+178
-85
lines changed

effekt/jvm/src/test/scala/effekt/LSPTests.scala

Lines changed: 49 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,10 +1421,10 @@ class LSPTests extends FunSuite {
14211421
qualifier = List(),
14221422
name = "x",
14231423
origin = BindingOrigin.Defined,
1424-
`type` = Some(
1425-
"Int"
1424+
signature = Some(
1425+
"x: Int"
14261426
),
1427-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Int</span>")
1427+
signatureHtml = Some("<span class=\"effekt-ident camel-case\">x</span>: <span class=\"effekt-ident pascal-case\">Int</span>"),
14281428
)
14291429
)
14301430

@@ -1433,26 +1433,32 @@ class LSPTests extends FunSuite {
14331433
qualifier = List(),
14341434
name = "bar",
14351435
origin = BindingOrigin.Defined,
1436-
`type` = Some(
1437-
"String => Int"
1436+
signature = Some(
1437+
"def bar(x: String): Int / {}"
14381438
),
1439-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">String</span> =&gt; <span class=\"effekt-ident pascal-case\">Int</span>"),
1439+
signatureHtml = Some(
1440+
"<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">bar</span>(<span class=\"effekt-ident camel-case\">x</span>: <span class=\"effekt-ident pascal-case\">String</span>): <span class=\"effekt-ident pascal-case\">Int</span> / {}"
1441+
)
14401442
),
14411443
TermBinding(
14421444
qualifier = List(),
14431445
name = "foo",
14441446
origin = BindingOrigin.Defined,
1445-
`type` = Some(
1446-
"Int => Bool"
1447+
signature = Some(
1448+
"def foo(x: Int): Bool / {}"
1449+
),
1450+
signatureHtml = Some(
1451+
"<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">foo</span>(<span class=\"effekt-ident camel-case\">x</span>: <span class=\"effekt-ident pascal-case\">Int</span>): <span class=\"effekt-ident pascal-case\">Bool</span> / {}"
14471452
),
1448-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Int</span> =&gt; <span class=\"effekt-ident pascal-case\">Bool</span>"),
14491453
),
14501454
TypeBinding(
14511455
qualifier = Nil,
14521456
name = "MyInt",
14531457
origin = BindingOrigin.Defined,
1454-
definition = "type MyInt = Int",
1455-
definitionHtml = "<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">MyInt</span> = <span class=\"effekt-ident pascal-case\">Int</span>",
1458+
signature = Some("type MyInt"),
1459+
signatureHtml = Some(
1460+
"<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">MyInt</span>"
1461+
),
14561462
)
14571463
)
14581464

@@ -1574,8 +1580,8 @@ class LSPTests extends FunSuite {
15741580
qualifier = List(),
15751581
name = "bar",
15761582
origin = BindingOrigin.Defined,
1577-
`type` = Some("() => Nothing"),
1578-
typeHtml = Some("() =&gt; <span class=\"effekt-ident pascal-case\">Nothing</span>")
1583+
signature = Some("def bar(): Nothing / {}"),
1584+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">bar</span>(): <span class=\"effekt-ident pascal-case\">Nothing</span> / {}"),
15791585
)
15801586
)
15811587

@@ -1604,8 +1610,8 @@ class LSPTests extends FunSuite {
16041610
qualifier = List(),
16051611
name = "x",
16061612
origin = BindingOrigin.Defined,
1607-
`type` = Some("Int"),
1608-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Int</span>")
1613+
signature = Some("x: Int"),
1614+
signatureHtml = None,
16091615
)
16101616
),
16111617
outer = Some(ScopeInfo(
@@ -1620,8 +1626,8 @@ class LSPTests extends FunSuite {
16201626
qualifier = List(),
16211627
name = "MyInt",
16221628
origin = BindingOrigin.Defined,
1623-
definition = "type MyInt = Int",
1624-
definitionHtml = "<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">MyInt</span> = <span class=\"effekt-ident pascal-case\">Int</span>"
1629+
signature = Some("type MyInt"),
1630+
signatureHtml = None,
16251631
)),
16261632
outer = None
16271633
))
@@ -1654,8 +1660,7 @@ class LSPTests extends FunSuite {
16541660
| "qualifier": [],
16551661
| "name": "x",
16561662
| "origin": "Defined",
1657-
| "type": "Int",
1658-
| "typeHtml": "<span class=\"effekt-ident pascal-case\">Int</span>",
1663+
| "signature": "x: Int",
16591664
| "kind": "Term"
16601665
| }
16611666
| ],
@@ -1670,8 +1675,7 @@ class LSPTests extends FunSuite {
16701675
| "qualifier": [],
16711676
| "name": "MyInt",
16721677
| "origin": "Defined",
1673-
| "definition": "type MyInt = Int",
1674-
| "definitionHtml": "<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">MyInt</span> = <span class=\"effekt-ident pascal-case\">Int</span>",
1678+
| "signature": "type MyInt",
16751679
| "kind": "Type"
16761680
| }
16771681
| ]
@@ -1929,97 +1933,77 @@ class LSPTests extends FunSuite {
19291933
qualifier = Nil,
19301934
name = "Foo1",
19311935
origin = "Defined",
1932-
definition = """type Foo1 {
1933-
def Foo1(theField: String): Foo1 / {}
1934-
}""",
1935-
definitionHtml = """<span class="effekt-keyword">type</span> <span class="effekt-ident pascal-case">Foo1</span> {
1936-
<span class="effekt-keyword">def</span> <span class="effekt-ident pascal-case">Foo1</span>(<span class="effekt-ident camel-case">theField</span>: <span class="effekt-ident pascal-case">String</span>): <span class="effekt-ident pascal-case">Foo1</span> / {}
1937-
}""",
1936+
signature = Some("type Foo1"),
1937+
signatureHtml = Some("<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">Foo1</span>"),
19381938
kind = "Type"
19391939
),
19401940
TermBinding(
19411941
qualifier = Nil,
19421942
name = "Foo1",
19431943
origin = "Defined",
1944-
`type` = Some(
1945-
value = "String => Foo1"
1944+
signature = Some(
1945+
"def Foo1(theField: String): Foo1 / {}"
19461946
),
1947-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">String</span> =&gt; <span class=\"effekt-ident pascal-case\">Foo1</span>"),
1947+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident pascal-case\">Foo1</span>(<span class=\"effekt-ident camel-case\">theField</span>: <span class=\"effekt-ident pascal-case\">String</span>): <span class=\"effekt-ident pascal-case\">Foo1</span> / {}"),
19481948
kind = "Term",
19491949
),
19501950
TermBinding(
19511951
qualifier = Nil,
19521952
name = "theField",
19531953
origin = "Defined",
1954-
`type` = Some(
1955-
value = "Foo1 => String"
1954+
signature = Some(
1955+
"def theField(Foo1: Foo1): String / {}"
19561956
),
1957-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Foo1</span> =&gt; <span class=\"effekt-ident pascal-case\">String</span>"),
1957+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">theField</span>(<span class=\"effekt-ident pascal-case\">Foo1</span>: <span class=\"effekt-ident pascal-case\">Foo1</span>): <span class=\"effekt-ident pascal-case\">String</span> / {}"),
19581958
kind = "Term",
19591959
),
19601960
TypeBinding(
19611961
qualifier = Nil,
19621962
name = "Foo2",
19631963
origin = "Defined",
1964-
definition = """type Foo2 {
1965-
def Foo2(theField: String): Foo2 / {}
1966-
}""",
1967-
definitionHtml = """<span class="effekt-keyword">type</span> <span class="effekt-ident pascal-case">Foo2</span> {
1968-
<span class="effekt-keyword">def</span> <span class="effekt-ident pascal-case">Foo2</span>(<span class="effekt-ident camel-case">theField</span>: <span class="effekt-ident pascal-case">String</span>): <span class="effekt-ident pascal-case">Foo2</span> / {}
1969-
}""",
1964+
signature = Some("type Foo2"),
1965+
signatureHtml = Some("<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">Foo2</span>"),
19701966
kind = "Type"
19711967
),
19721968
TermBinding(
19731969
qualifier = Nil,
19741970
name = "Foo2",
19751971
origin = "Defined",
1976-
`type` = Some(
1977-
value = "String => Foo2"
1978-
),
1979-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">String</span> =&gt; <span class=\"effekt-ident pascal-case\">Foo2</span>"),
1980-
kind = "Term",
1972+
signature = Some("def Foo2(theField: String): Foo2 / {}"),
1973+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident pascal-case\">Foo2</span>(<span class=\"effekt-ident camel-case\">theField</span>: <span class=\"effekt-ident pascal-case\">String</span>): <span class=\"effekt-ident pascal-case\">Foo2</span> / {}"),
1974+
kind = "Term"
19811975
),
19821976
TermBinding(
19831977
qualifier = Nil,
19841978
name = "theField",
19851979
origin = "Defined",
1986-
`type` = Some(
1987-
value = "Foo2 => String"
1988-
),
1989-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Foo2</span> =&gt; <span class=\"effekt-ident pascal-case\">String</span>"),
1990-
kind = "Term",
1980+
signature = Some("def theField(Foo2: Foo2): String / {}"),
1981+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">theField</span>(<span class=\"effekt-ident pascal-case\">Foo2</span>: <span class=\"effekt-ident pascal-case\">Foo2</span>): <span class=\"effekt-ident pascal-case\">String</span> / {}"),
1982+
kind = "Term"
19911983
),
19921984
TypeBinding(
19931985
qualifier = Nil,
19941986
name = "Bar",
19951987
origin = "Defined",
1996-
definition = """type Bar {
1997-
def Bar(theField: Int): Bar / {}
1998-
}""",
1999-
definitionHtml = """<span class="effekt-keyword">type</span> <span class="effekt-ident pascal-case">Bar</span> {
2000-
<span class="effekt-keyword">def</span> <span class="effekt-ident pascal-case">Bar</span>(<span class="effekt-ident camel-case">theField</span>: <span class="effekt-ident pascal-case">Int</span>): <span class="effekt-ident pascal-case">Bar</span> / {}
2001-
}""",
1988+
signature = Some("type Bar"),
1989+
signatureHtml = Some("<span class=\"effekt-keyword\">type</span> <span class=\"effekt-ident pascal-case\">Bar</span>"),
20021990
kind = "Type"
20031991
),
20041992
TermBinding(
20051993
qualifier = Nil,
20061994
name = "Bar",
20071995
origin = "Defined",
2008-
`type` = Some(
2009-
value = "Int => Bar"
2010-
),
2011-
typeHtml = Some("<span class=\"effekt-ident pascal-case\">Int</span> =&gt; <span class=\"effekt-ident pascal-case\">Bar</span>"),
2012-
kind = "Term",
1996+
signature = Some("def Bar(theField: Int): Bar / {}"),
1997+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident pascal-case\">Bar</span>(<span class=\"effekt-ident camel-case\">theField</span>: <span class=\"effekt-ident pascal-case\">Int</span>): <span class=\"effekt-ident pascal-case\">Bar</span> / {}"),
1998+
kind = "Term"
20131999
),
20142000
TermBinding(
20152001
qualifier = Nil,
20162002
name = "main",
20172003
origin = "Defined",
2018-
`type` = Some(
2019-
value = "() => Nothing"
2020-
),
2021-
typeHtml = Some("() =&gt; <span class=\"effekt-ident pascal-case\">Nothing</span>"),
2022-
kind = "Term",
2004+
signature = Some("def main(): Nothing / {}"),
2005+
signatureHtml = Some("<span class=\"effekt-keyword\">def</span> <span class=\"effekt-ident camel-case\">main</span>(): <span class=\"effekt-ident pascal-case\">Nothing</span> / {}"),
2006+
kind = "Term"
20232007
)
20242008
)
20252009

effekt/shared/src/main/scala/effekt/Intelligence.scala

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ trait Intelligence {
189189
}
190190

191191
def allBindings(origin: String, bindings: Bindings, path: List[String] = Nil)(using C: Context): List[BindingInfo] =
192-
val symbols = allSymbols(origin, bindings, path)
192+
val symbols = allSymbols(origin, bindings, path).distinctBy(s => s._3)
193193

194194
val sorted = if (origin == BindingOrigin.Imported) {
195195
symbols.sortBy(_._1.toLowerCase())
@@ -200,24 +200,28 @@ trait Intelligence {
200200
})
201201
}
202202

203-
sorted.flatMap((name, path, sym) => sym match {
203+
def symbolToBindingInfos(name: String, path: List[String], sym: TypeSymbol | TermSymbol)(using C: Context): List[BindingInfo] =
204204
// TODO this is extremely hacky, printing is not defined for all types at the moment
205-
case sym: TypeSymbol => try {
206-
val definition = DeclPrinter(sym)
207-
val definitionHtml = HtmlHighlight(definition)
208-
Some(TypeBinding(path, name, origin, definition, definitionHtml))
209-
} catch { case e => None }
210-
case sym: ValueSymbol => {
211-
val `type` = C.valueTypeOption(sym).map(t => pp"${t}")
212-
val typeHtml = `type`.map(HtmlHighlight(_))
213-
Some(TermBinding(path, name, origin, `type`, typeHtml))
205+
val signature = try { Some(SignaturePrinter(sym)) } catch { case e: Throwable => None }
206+
val signatureHtml = signature.map(sig => HtmlHighlight(sig))
207+
val out = sym match {
208+
case sym: TypeSymbol => List(TypeBinding(path, name, origin, signature, signatureHtml))
209+
case sym: ValueSymbol => List(TermBinding(path, name, origin, signature, signatureHtml))
210+
case sym: BlockSymbol => List(TermBinding(path, name, origin, signature, signatureHtml))
214211
}
215-
case sym: BlockSymbol => {
216-
val `type` = C.blockTypeOption(sym).map(t => pp"${t}")
217-
val typeHtml = `type`.map(HtmlHighlight(_))
218-
Some(TermBinding(path, name, origin, `type`, typeHtml))
212+
sym match {
213+
case Interface(name, tparams, ops, decl) if !(ops.length == 1 && ops.head.name.name == name.name) => {
214+
val opsInfos = ops.map { op =>
215+
val signature = Some(SignaturePrinter(op))
216+
val signatureHtml = signature.map(sig => HtmlHighlight(sig))
217+
TermBinding(path, op.name.name, origin, signature, signatureHtml)
218+
}
219+
out ++ opsInfos
220+
}
221+
case _ => out
219222
}
220-
}).toList
223+
224+
sorted.flatMap(symbolToBindingInfos).toList
221225

222226
def allSymbols(origin: String, bindings: Bindings, path: List[String] = Nil)(using C: Context): Array[(String, List[String], TypeSymbol | TermSymbol)] = {
223227
bindings.types.toArray.map((name, sym) => (name, path, sym))
@@ -464,23 +468,25 @@ object Intelligence {
464468
val qualifier: List[String]
465469
val name: String
466470
val origin: String
471+
val signature: Option[String]
472+
val signatureHtml: Option[String]
467473
val kind: String
468474
}
469475

470476
case class TermBinding(
471477
qualifier: List[String],
472478
name: String,
473479
origin: String,
474-
`type`: Option[String],
475-
typeHtml: Option[String],
480+
signature: Option[String] = None,
481+
signatureHtml: Option[String],
476482
kind: String = BindingKind.Term
477483
) extends BindingInfo
478484
case class TypeBinding(
479485
qualifier: List[String],
480486
name: String,
481487
origin: String,
482-
definition: String,
483-
definitionHtml: String,
488+
signature: Option[String] = None,
489+
signatureHtml: Option[String],
484490
kind: String = BindingKind.Type
485491
) extends BindingInfo
486492

0 commit comments

Comments
 (0)