microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.0.10-rc

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

language_service/src/display.rs

704lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::qsc_utils::{find_item, Compilation};
5use qsc::{
6 ast,
7 hir::{self},
8};
9use std::{
10 fmt::{Display, Formatter, Result},
11 rc::Rc,
12};
13
14pub(crate) struct CodeDisplay<'a> {
15 pub(crate) compilation: &'a Compilation,
16}
17
18#[allow(clippy::unused_self)]
19impl<'a> CodeDisplay<'a> {
20 pub(crate) fn hir_callable_decl(&self, decl: &'a hir::CallableDecl) -> impl Display + 'a {
21 HirCallableDecl {
22 compilation: self.compilation,
23 decl,
24 }
25 }
26
27 pub(crate) fn ast_callable_decl(&self, decl: &'a ast::CallableDecl) -> impl Display + 'a {
28 AstCallableDecl {
29 compilation: self.compilation,
30 decl,
31 }
32 }
33
34 pub(crate) fn ident_ty_id(
35 &self,
36 ident: &'a ast::Ident,
37 ty_id: ast::NodeId,
38 ) -> impl Display + 'a {
39 IdentTyId {
40 compilation: self.compilation,
41 ident,
42 ty_id,
43 }
44 }
45
46 pub(crate) fn path_ty_id(&self, path: &'a ast::Path, ty_id: ast::NodeId) -> impl Display + 'a {
47 PathTyId {
48 compilation: self.compilation,
49 path,
50 ty_id,
51 }
52 }
53
54 pub(crate) fn ident_ty(&self, ident: &'a ast::Ident, ty: &'a ast::Ty) -> impl Display + 'a {
55 IdentTy { ident, ty }
56 }
57
58 pub(crate) fn ident_ty_def(
59 &self,
60 ident: &'a ast::Ident,
61 def: &'a ast::TyDef,
62 ) -> impl Display + 'a {
63 IdentTyDef { ident, def }
64 }
65
66 pub(crate) fn hir_udt(&self, udt: &'a hir::ty::Udt) -> impl Display + 'a {
67 HirUdt {
68 compilation: self.compilation,
69 udt,
70 }
71 }
72
73 pub(crate) fn hir_pat(&self, pat: &'a hir::Pat) -> impl Display + 'a {
74 HirPat {
75 compilation: self.compilation,
76 pat,
77 }
78 }
79
80 pub(crate) fn get_param_offset(&self, decl: &hir::CallableDecl) -> u32 {
81 HirCallableDecl {
82 compilation: self.compilation,
83 decl,
84 }
85 .get_param_offset()
86 }
87
88 // The rest of the display implementations are not made public b/c they're not used,
89 // but there's no reason they couldn't be
90}
91
92// Display impls for each syntax/hir element we may encounter
93
94struct IdentTy<'a> {
95 ident: &'a ast::Ident,
96 ty: &'a ast::Ty,
97}
98
99impl<'a> Display for IdentTy<'a> {
100 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
101 write!(f, "{} : {}", self.ident.name, AstTy { ty: self.ty },)
102 }
103}
104
105struct IdentTyId<'a> {
106 compilation: &'a Compilation,
107 ident: &'a ast::Ident,
108 ty_id: ast::NodeId,
109}
110
111impl<'a> Display for IdentTyId<'a> {
112 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
113 write!(
114 f,
115 "{} : {}",
116 self.ident.name,
117 TyId {
118 ty_id: self.ty_id,
119 compilation: self.compilation
120 },
121 )
122 }
123}
124
125struct PathTyId<'a> {
126 compilation: &'a Compilation,
127 path: &'a ast::Path,
128 ty_id: ast::NodeId,
129}
130
131impl<'a> Display for PathTyId<'a> {
132 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
133 write!(
134 f,
135 "{} : {}",
136 &Path { path: self.path },
137 TyId {
138 ty_id: self.ty_id,
139 compilation: self.compilation
140 },
141 )
142 }
143}
144
145struct HirCallableDecl<'a, 'b> {
146 compilation: &'a Compilation,
147 decl: &'b hir::CallableDecl,
148}
149
150impl HirCallableDecl<'_, '_> {
151 fn get_param_offset(&self) -> u32 {
152 let offset = match self.decl.kind {
153 hir::CallableKind::Function => "function".len(),
154 hir::CallableKind::Operation => "operation".len(),
155 } + 2; // this is for the space between keyword and name plus the opening paren
156 u32::try_from(offset + self.decl.name.name.len())
157 .expect("failed to cast usize to u32 while calculating parameter offset")
158 }
159}
160
161impl Display for HirCallableDecl<'_, '_> {
162 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
163 let kind = match self.decl.kind {
164 hir::CallableKind::Function => "function",
165 hir::CallableKind::Operation => "operation",
166 };
167
168 write!(f, "{} {}", kind, self.decl.name.name)?;
169 let input = HirPat {
170 pat: &self.decl.input,
171 compilation: self.compilation,
172 };
173 if matches!(self.decl.input.kind, hir::PatKind::Tuple(_)) {
174 write!(f, "{input}")?;
175 } else {
176 write!(f, "({input})")?;
177 }
178 write!(
179 f,
180 " : {}{}",
181 HirTy {
182 ty: &self.decl.output,
183 compilation: self.compilation
184 },
185 FunctorSetValue {
186 functors: self.decl.functors,
187 },
188 )
189 }
190}
191
192struct AstCallableDecl<'a> {
193 compilation: &'a Compilation,
194 decl: &'a ast::CallableDecl,
195}
196
197impl<'a> Display for AstCallableDecl<'a> {
198 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
199 let kind = match self.decl.kind {
200 ast::CallableKind::Function => "function",
201 ast::CallableKind::Operation => "operation",
202 };
203
204 let functors = ast_callable_functors(self.decl);
205 let functors = FunctorSetValue { functors };
206
207 write!(f, "{} {}", kind, self.decl.name.name)?;
208 let input = AstPat {
209 pat: &self.decl.input,
210 compilation: self.compilation,
211 };
212 if matches!(*self.decl.input.kind, ast::PatKind::Tuple(_)) {
213 write!(f, "{input}")?;
214 } else {
215 write!(f, "({input})")?;
216 }
217 write!(
218 f,
219 " : {}{}",
220 AstTy {
221 ty: &self.decl.output
222 },
223 functors,
224 )
225 }
226}
227
228struct HirPat<'a> {
229 pat: &'a hir::Pat,
230 compilation: &'a Compilation,
231}
232
233impl<'a> Display for HirPat<'a> {
234 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
235 let ty = HirTy {
236 ty: &self.pat.ty,
237 compilation: self.compilation,
238 };
239 match &self.pat.kind {
240 hir::PatKind::Bind(name) => write!(f, "{} : {ty}", name.name),
241 hir::PatKind::Discard => write!(f, "_ : {ty}"),
242 hir::PatKind::Tuple(items) => {
243 let mut elements = items.iter();
244 if let Some(elem) = elements.next() {
245 write!(
246 f,
247 "({}",
248 HirPat {
249 pat: elem,
250 compilation: self.compilation
251 }
252 )?;
253 for elem in elements {
254 write!(
255 f,
256 ", {}",
257 HirPat {
258 pat: elem,
259 compilation: self.compilation
260 }
261 )?;
262 }
263 write!(f, ")")
264 } else {
265 write!(f, "()")
266 }
267 }
268 }
269 }
270}
271
272struct AstPat<'a> {
273 pat: &'a ast::Pat,
274 compilation: &'a Compilation,
275}
276
277impl<'a> Display for AstPat<'a> {
278 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
279 match &*self.pat.kind {
280 ast::PatKind::Bind(ident, anno) => match anno {
281 Some(ty) => write!(f, "{}", IdentTy { ident, ty }),
282 None => write!(
283 f,
284 "{}",
285 IdentTyId {
286 compilation: self.compilation,
287 ident,
288 ty_id: self.pat.id
289 }
290 ),
291 },
292 ast::PatKind::Discard(anno) => match anno {
293 Some(ty) => write!(f, "{}", AstTy { ty }),
294 None => write!(
295 f,
296 "_ : {}",
297 TyId {
298 ty_id: self.pat.id,
299 compilation: self.compilation
300 }
301 ),
302 },
303 ast::PatKind::Elided => write!(f, "..."),
304 ast::PatKind::Paren(item) => write!(
305 f,
306 "{}",
307 AstPat {
308 pat: item,
309 compilation: self.compilation
310 }
311 ),
312 ast::PatKind::Tuple(items) => {
313 let mut elements = items.iter();
314 if let Some(elem) = elements.next() {
315 write!(
316 f,
317 "({}",
318 AstPat {
319 pat: elem,
320 compilation: self.compilation
321 }
322 )?;
323 for elem in elements {
324 write!(
325 f,
326 ", {}",
327 AstPat {
328 pat: elem,
329 compilation: self.compilation
330 }
331 )?;
332 }
333 write!(f, ")")
334 } else {
335 write!(f, "()")
336 }
337 }
338 }
339 }
340}
341
342struct IdentTyDef<'a> {
343 ident: &'a ast::Ident,
344 def: &'a ast::TyDef,
345}
346
347impl<'a> Display for IdentTyDef<'a> {
348 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
349 write!(
350 f,
351 "newtype {} = {}",
352 self.ident.name,
353 TyDef { def: self.def }
354 )
355 }
356}
357
358struct HirUdt<'a> {
359 compilation: &'a Compilation,
360 udt: &'a hir::ty::Udt,
361}
362
363impl<'a> Display for HirUdt<'a> {
364 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
365 let udt_def = UdtDef::new(self.compilation, &self.udt.definition);
366 write!(f, "newtype {} = {}", self.udt.name, udt_def)
367 }
368}
369
370struct UdtDef<'a> {
371 compilation: &'a Compilation,
372 name: Option<Rc<str>>,
373 kind: UdtDefKind<'a>,
374}
375
376enum UdtDefKind<'a> {
377 SingleTy(&'a hir::ty::Ty),
378 TupleTy(Vec<UdtDef<'a>>),
379}
380
381impl<'a> UdtDef<'a> {
382 pub fn new(compilation: &'a Compilation, def: &'a hir::ty::UdtDef) -> Self {
383 match &def.kind {
384 hir::ty::UdtDefKind::Field(field) => UdtDef {
385 compilation,
386 name: field.name.as_ref().cloned(),
387 kind: UdtDefKind::SingleTy(&field.ty),
388 },
389 hir::ty::UdtDefKind::Tuple(defs) => UdtDef {
390 compilation,
391 name: None,
392 kind: UdtDefKind::TupleTy(
393 defs.iter().map(|f| UdtDef::new(compilation, f)).collect(),
394 ),
395 },
396 }
397 }
398}
399
400impl Display for UdtDef<'_> {
401 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
402 if let Some(name) = &self.name {
403 write!(f, "{name}: ")?;
404 }
405
406 match &self.kind {
407 UdtDefKind::SingleTy(ty) => {
408 write!(
409 f,
410 "{}",
411 HirTy {
412 ty,
413 compilation: self.compilation
414 }
415 )?;
416 }
417 UdtDefKind::TupleTy(defs) => {
418 let mut elements = defs.iter();
419 if let Some(elem) = elements.next() {
420 write!(f, "({elem}")?;
421 for elem in elements {
422 write!(f, ", {elem}")?;
423 }
424 write!(f, ")")?;
425 } else {
426 write!(f, "Unit")?;
427 }
428 }
429 }
430 Ok(())
431 }
432}
433
434struct FunctorSet<'a> {
435 functor_set: &'a hir::ty::FunctorSet,
436}
437
438impl<'a> Display for FunctorSet<'a> {
439 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
440 if *self.functor_set == hir::ty::FunctorSet::Value(hir::ty::FunctorSetValue::Empty) {
441 Ok(())
442 } else {
443 write!(f, " is {}", self.functor_set)
444 }
445 }
446}
447
448struct FunctorSetValue {
449 functors: hir::ty::FunctorSetValue,
450}
451
452impl Display for FunctorSetValue {
453 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
454 if let hir::ty::FunctorSetValue::Empty = self.functors {
455 Ok(())
456 } else {
457 write!(f, " is {}", self.functors)
458 }
459 }
460}
461
462struct HirTy<'a> {
463 ty: &'a hir::ty::Ty,
464 compilation: &'a Compilation,
465}
466
467impl<'a> Display for HirTy<'a> {
468 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
469 // This is very similar to the Display impl for Ty, except that UDTs are resolved to their names.
470 match self.ty {
471 hir::ty::Ty::Array(item) => {
472 write!(
473 f,
474 "{}[]",
475 HirTy {
476 compilation: self.compilation,
477 ty: item,
478 }
479 )
480 }
481 hir::ty::Ty::Arrow(arrow) => {
482 let input = HirTy {
483 compilation: self.compilation,
484 ty: &arrow.input,
485 };
486 let output = HirTy {
487 compilation: self.compilation,
488 ty: &arrow.output,
489 };
490 let functors = FunctorSet {
491 functor_set: &arrow.functors,
492 };
493 let arrow = match arrow.kind {
494 hir::CallableKind::Function => "->",
495 hir::CallableKind::Operation => "=>",
496 };
497 write!(f, "({input} {arrow} {output}{functors})",)
498 }
499 hir::ty::Ty::Tuple(tys) => {
500 if tys.is_empty() {
501 write!(f, "Unit")
502 } else {
503 write!(f, "(")?;
504 for (count, ty) in tys.iter().enumerate() {
505 if count != 0 {
506 write!(f, ", ")?;
507 }
508 write!(
509 f,
510 "{}",
511 HirTy {
512 compilation: self.compilation,
513 ty
514 }
515 )?;
516 }
517 write!(f, ")")
518 }
519 }
520 hir::ty::Ty::Udt(res) => match res {
521 hir::Res::Item(item_id) => {
522 if let (Some(item), _) = find_item(self.compilation, item_id) {
523 match &item.kind {
524 hir::ItemKind::Ty(ident, _) => write!(f, "{}", ident.name),
525 _ => panic!("UDT has invalid resolution."),
526 }
527 } else {
528 write!(f, "?")
529 }
530 }
531 _ => panic!("UDT has invalid resolution."),
532 },
533 _ => write!(f, "{}", self.ty),
534 }
535 }
536}
537
538struct TyId<'a> {
539 ty_id: ast::NodeId,
540 compilation: &'a Compilation,
541}
542
543impl<'a> Display for TyId<'a> {
544 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
545 if let Some(ty) = self.compilation.unit.ast.tys.terms.get(self.ty_id) {
546 write!(
547 f,
548 "{}",
549 HirTy {
550 compilation: self.compilation,
551 ty
552 }
553 )
554 } else {
555 write!(f, "?")
556 }
557 }
558}
559
560struct AstTy<'a> {
561 ty: &'a ast::Ty,
562}
563
564impl<'a> Display for AstTy<'a> {
565 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
566 match self.ty.kind.as_ref() {
567 ast::TyKind::Array(ty) => write!(f, "{}[]", AstTy { ty }),
568 ast::TyKind::Arrow(kind, input, output, functors) => {
569 let arrow = match kind {
570 ast::CallableKind::Function => "->",
571 ast::CallableKind::Operation => "=>",
572 };
573 write!(
574 f,
575 "({} {} {}{})",
576 AstTy { ty: input },
577 arrow,
578 AstTy { ty: output },
579 FunctorExpr { functors }
580 )
581 }
582 ast::TyKind::Hole => write!(f, "_"),
583 ast::TyKind::Paren(ty) => write!(f, "{}", AstTy { ty }),
584 ast::TyKind::Path(path) => write!(f, "{}", Path { path }),
585 ast::TyKind::Param(id) => write!(f, "{}", id.name),
586 ast::TyKind::Tuple(tys) => {
587 if tys.is_empty() {
588 write!(f, "Unit")
589 } else {
590 write!(f, "(")?;
591 for (count, def) in tys.iter().enumerate() {
592 if count != 0 {
593 write!(f, ", ")?;
594 }
595 write!(f, "{}", AstTy { ty: def })?;
596 }
597 write!(f, ")")
598 }
599 }
600 }
601 }
602}
603
604struct FunctorExpr<'a> {
605 functors: &'a Option<Box<ast::FunctorExpr>>,
606}
607
608impl<'a> Display for FunctorExpr<'a> {
609 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
610 match self.functors {
611 Some(functors) => {
612 let functors = eval_functor_expr(functors);
613 write!(f, "{}", FunctorSetValue { functors })
614 }
615 None => Ok(()),
616 }
617 }
618}
619
620struct Path<'a> {
621 path: &'a ast::Path,
622}
623
624impl<'a> Display for Path<'a> {
625 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
626 match self.path.namespace.as_ref() {
627 Some(ns) => write!(f, "{ns}.{}", self.path.name.name),
628 None => write!(f, "{}", self.path.name.name),
629 }
630 }
631}
632
633struct TyDef<'a> {
634 def: &'a ast::TyDef,
635}
636
637impl<'a> Display for TyDef<'a> {
638 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
639 match self.def.kind.as_ref() {
640 ast::TyDefKind::Field(name, ty) => match name {
641 Some(name) => write!(f, "{} : {}", name.name, AstTy { ty }),
642 None => write!(f, "{}", AstTy { ty }),
643 },
644 ast::TyDefKind::Paren(def) => write!(f, "{}", TyDef { def }),
645 ast::TyDefKind::Tuple(tys) => {
646 if tys.is_empty() {
647 write!(f, "Unit")
648 } else {
649 write!(f, "(")?;
650 for (count, def) in tys.iter().enumerate() {
651 if count != 0 {
652 write!(f, ", ")?;
653 }
654 write!(f, "{}", TyDef { def })?;
655 }
656 write!(f, ")")
657 }
658 }
659 }
660 }
661}
662
663//
664// helpers that don't manipulate any strings
665//
666
667fn ast_callable_functors(callable: &ast::CallableDecl) -> hir::ty::FunctorSetValue {
668 let mut functors = callable
669 .functors
670 .as_ref()
671 .map_or(hir::ty::FunctorSetValue::Empty, |f| {
672 eval_functor_expr(f.as_ref())
673 });
674
675 if let ast::CallableBody::Specs(specs) = callable.body.as_ref() {
676 for spec in specs.iter() {
677 let spec_functors = match spec.spec {
678 ast::Spec::Body => hir::ty::FunctorSetValue::Empty,
679 ast::Spec::Adj => hir::ty::FunctorSetValue::Adj,
680 ast::Spec::Ctl => hir::ty::FunctorSetValue::Ctl,
681 ast::Spec::CtlAdj => hir::ty::FunctorSetValue::CtlAdj,
682 };
683 functors = functors.union(&spec_functors);
684 }
685 }
686
687 functors
688}
689
690fn eval_functor_expr(expr: &ast::FunctorExpr) -> hir::ty::FunctorSetValue {
691 match expr.kind.as_ref() {
692 ast::FunctorExprKind::BinOp(op, lhs, rhs) => {
693 let lhs_functors = eval_functor_expr(lhs);
694 let rhs_functors = eval_functor_expr(rhs);
695 match op {
696 ast::SetOp::Union => lhs_functors.union(&rhs_functors),
697 ast::SetOp::Intersect => lhs_functors.intersect(&rhs_functors),
698 }
699 }
700 ast::FunctorExprKind::Lit(ast::Functor::Adj) => hir::ty::FunctorSetValue::Adj,
701 ast::FunctorExprKind::Lit(ast::Functor::Ctl) => hir::ty::FunctorSetValue::Ctl,
702 ast::FunctorExprKind::Paren(inner) => eval_functor_expr(inner),
703 }
704}
705