dada_ir_sym/
well_known.rs1use dada_ir_ast::{
2 ast::Identifier,
3 diagnostic::{Diagnostic, Errors, Reported},
4 span::{Span, Spanned},
5};
6
7use crate::{
8 ir::{
9 classes::{SymAggregate, SymClassMember},
10 functions::SymFunction,
11 module::{SymItem, SymModule},
12 types::SymGenericKind,
13 },
14 prelude::Symbol,
15};
16
17pub fn prelude_span(db: &dyn crate::Db) -> Span<'_> {
20 prelude_module(db).span(db)
21}
22
23fn prelude_module(db: &dyn crate::Db) -> SymModule<'_> {
25 let krate = db.root().libdada_crate(db);
26 let identifier = Identifier::prelude(db);
27 db.source_file(krate, &[identifier]).symbol(db)
28}
29
30fn prelude_member<'db>(db: &'db dyn crate::Db, name: &str) -> Errors<SymItem<'db>> {
33 let identifier = Identifier::new(db, name);
34 let module = prelude_module(db);
35 module
36 .items(db)
37 .find(|item| item.name(db) == identifier)
38 .ok_or_else(|| report_not_found(db, module, &format!("`{name}` in the `libdada` prelude")))
39}
40
41#[salsa::tracked]
43pub fn string_class<'db>(db: &'db dyn crate::Db) -> Errors<SymAggregate<'db>> {
44 match prelude_member(db, "String")? {
45 SymItem::SymClass(class) if class.is_class(db) => {
46 if !class.symbols(db).has_generics_of_kind(db, &[]) {
47 return Err(report_unexpected(
48 db,
49 class,
50 "String",
51 "it has generic parameters",
52 ));
53 }
54 Ok(class)
55 }
56 m => Err(report_unexpected(db, m, "String", "it is not a class")),
57 }
58}
59
60#[salsa::tracked]
62pub fn string_literal_fn<'db>(db: &'db dyn crate::Db) -> Errors<SymFunction<'db>> {
63 let string_class = string_class(db)?;
64 let literal_fn = string_class
65 .inherent_member_str(db, "literal")
66 .ok_or_else(|| {
67 report_unexpected(
68 db,
69 string_class,
70 "String",
71 "does not have a `literal` member",
72 )
73 })?;
74 match literal_fn {
75 SymClassMember::SymFunction(function) => {
76 if !function.symbols(db).has_generics_of_kind(db, &[]) {
77 return Err(report_unexpected(
78 db,
79 function,
80 "String",
81 "`literal` should not have generic parameters",
82 ));
83 }
84 Ok(function)
85 }
86 m => Err(report_unexpected(
87 db,
88 m,
89 "String",
90 "`literal` is not a function",
91 )),
92 }
93}
94
95#[salsa::tracked]
97pub fn pointer_struct<'db>(db: &'db dyn crate::Db) -> Errors<SymAggregate<'db>> {
98 match prelude_member(db, "Pointer")? {
99 SymItem::SymClass(class) if class.is_struct(db) => {
100 if !class
101 .symbols(db)
102 .has_generics_of_kind(db, &[SymGenericKind::Type])
103 {
104 return Err(report_unexpected(
105 db,
106 class,
107 "Pointer",
108 "it should have 1 generic parameter",
109 ));
110 }
111 Ok(class)
112 }
113 m => Err(report_unexpected(db, m, "Pointer", "it is not a struct")),
114 }
115}
116
117fn report_not_found<'db>(db: &'db dyn crate::Db, module: SymModule<'db>, name: &str) -> Reported {
118 let module_span = module.span(db);
119 Diagnostic::error(db, module_span, format!("could not find {name}")).report(db)
120}
121
122fn report_unexpected<'db>(
123 db: &'db dyn crate::Db,
124 spanned: impl Spanned<'db>,
125 name: &str,
126 problem: &str,
127) -> Reported {
128 let span = spanned.span(db);
129 Diagnostic::error(db, span, format!("found {name} but {problem}")).report(db)
130}