1use std::collections::HashSet;
3use std::ops::Range;
4use std::rc::Rc;
5
6use serde_json::{Value, json};
7use zincite_lint::{
8 BindingFacts, BindingResolution, CallOutcome, CallableFacts, DeclarationId, FileId,
9 Instantiation, InstantiationFacts, ModelContext, ModelFacts, ReferenceKind, SourceDiagnostic,
10 SourceKind, SourceLocation, TypeInst, TypeKind,
11};
12use zincite_syntax::{FileMode, SyntaxNode};
13
14use crate::inspection::{check_collection, kind_name, type_error};
15use crate::language::{Predicate, PredicateKind, Stage, StageKind};
16use crate::{ErrorLocation, Input, Limits, Query, QueryError, QueryResult, Selection, Work};
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum SemanticEntity {
21 Declaration(DeclarationId),
22 Reference(usize),
24}
25
26#[derive(Clone, Debug)]
28pub enum SemanticSubject<'a> {
29 Entity(SemanticEntity),
30 Node {
31 file: FileId,
32 node: &'a SyntaxNode,
33 location: SourceLocation,
34 },
35}
36
37#[derive(Clone, Debug)]
38pub struct SemanticType<'a> {
39 pub subject: SemanticSubject<'a>,
40 pub ty: Option<TypeInst>,
42}
43
44#[derive(Clone, Debug)]
45pub struct SemanticInstantiation<'a> {
46 pub subject: SemanticSubject<'a>,
47 pub instantiation: Instantiation,
48 pub reason: Option<String>,
49}
50
51#[derive(Debug)]
52pub enum SemanticStream<'a> {
53 Inspection(Box<QueryResult<'a>>),
55 Entities(Vec<SemanticEntity>),
56 Types(Vec<SemanticType<'a>>),
57 Instantiations(Vec<SemanticInstantiation<'a>>),
58}
59
60#[derive(Debug)]
64pub struct SemanticResult<'a> {
65 model: &'a ModelContext,
66 pub(crate) facts: Rc<ModelFacts<'a>>,
67 bindings_requested: bool,
68 callables_requested: bool,
69 instantiations_requested: bool,
70 body_callables: Option<CallableFacts>,
71 reference_order: Option<Vec<usize>>,
72 pub(crate) stream: SemanticStream<'a>,
73 limitations: Vec<SourceDiagnostic>,
74 json: bool,
75 pub(crate) incomplete_observation: Option<std::sync::Arc<QueryError>>,
76}
77
78enum ReferenceEndpoint {
79 Declaration(DeclarationId),
80 Intrinsic,
81 Uncertain(SourceLocation, String),
82}
83
84impl<'a> SemanticResult<'a> {
85 pub fn model(&self) -> &'a ModelContext {
86 self.model
87 }
88 pub fn bindings(&self) -> Option<&BindingFacts> {
89 self.bindings_requested.then(|| self.facts.bindings())
90 }
91 pub fn callables(&self) -> Option<&CallableFacts> {
92 self.callables_requested.then(|| {
93 self.body_callables
94 .as_ref()
95 .unwrap_or_else(|| self.facts.source_callables())
96 })
97 }
98 pub fn instantiation_facts(&self) -> Option<&InstantiationFacts> {
99 self.instantiations_requested
100 .then(|| self.facts.instantiations())
101 }
102 pub fn stream(&self) -> &SemanticStream<'a> {
103 &self.stream
104 }
105 pub fn limitations(&self) -> &[SourceDiagnostic] {
106 &self.limitations
107 }
108 pub fn is_complete(&self) -> bool {
109 self.limitations.is_empty()
110 }
111
112 pub fn location(&self, entity: SemanticEntity) -> &SourceLocation {
114 match entity {
115 SemanticEntity::Declaration(id) => {
116 &self.bindings().unwrap().declarations[id.0].location
117 }
118 SemanticEntity::Reference(id) => &self.bindings().unwrap().references[id].location,
119 }
120 }
121 pub fn file(&self, entity: SemanticEntity) -> FileId {
122 match entity {
123 SemanticEntity::Declaration(id) => self.bindings().unwrap().declarations[id.0].file,
124 SemanticEntity::Reference(id) => self.bindings().unwrap().references[id].file,
125 }
126 }
127 pub fn source_bytes(&self, entity: SemanticEntity) -> &[u8] {
129 let file = &self.model.files[self.file(entity)];
130 let range = match entity {
131 SemanticEntity::Declaration(id) => self.bindings().unwrap().declarations[id.0]
132 .syntax_range
133 .clone(),
134 SemanticEntity::Reference(_) => {
135 let range = &self.location(entity).range;
136 range.start - file.byte_offset..range.end - file.byte_offset
137 }
138 };
139 &file.source_bytes()[range]
140 }
141 fn name(&self, entity: SemanticEntity) -> &str {
142 match entity {
143 SemanticEntity::Declaration(id) => &self.bindings().unwrap().declarations[id.0].name,
144 SemanticEntity::Reference(id) => &self.bindings().unwrap().references[id].name,
145 }
146 }
147 fn subject_location(&self, subject: &SemanticSubject<'_>) -> SourceLocation {
148 match subject {
149 SemanticSubject::Entity(entity) => self.location(*entity).clone(),
150 SemanticSubject::Node { location, .. } => location.clone(),
151 }
152 }
153 fn subject_file(&self, subject: &SemanticSubject<'_>) -> FileId {
154 match subject {
155 SemanticSubject::Entity(entity) => self.file(*entity),
156 SemanticSubject::Node { file, .. } => *file,
157 }
158 }
159 pub(crate) fn subject_bytes(&self, subject: &SemanticSubject<'_>) -> &[u8] {
160 match subject {
161 SemanticSubject::Entity(entity) => self.source_bytes(*entity),
162 SemanticSubject::Node { file, node, .. } => {
163 &self.model.files[*file].source_bytes()[node.range()]
164 }
165 }
166 }
167 fn limit(
168 &mut self,
169 location: SourceLocation,
170 message: impl Into<String>,
171 work: &mut Work,
172 stage: &Stage,
173 limits: Limits,
174 ) -> Result<(), QueryError> {
175 let message = message.into();
176 for existing in &self.limitations {
177 work.visit(&stage.range)?;
178 if existing.location == location && existing.message == message {
179 return Ok(());
180 }
181 }
182 check_collection(self.limitations.len(), limits.collection, &stage.range)?;
183 work.produce(1, &stage.range)?;
184 work.spend(message.len().max(1), &stage.range)?;
185 self.limitations
186 .push(SourceDiagnostic { location, message });
187 Ok(())
188 }
189
190 pub(crate) fn render(&self) -> Vec<u8> {
191 if self.json {
192 let value = json!({
193 "complete": self.is_complete(),
194 "limitations": self.limitations.iter().map(|d| json!({"file": d.location.path.to_string_lossy(), "range": range_json(&d.location.range), "line": d.location.line, "column": d.location.column, "message": d.message})).collect::<Vec<_>>(),
195 "result": self.json_value().expect("semantic JSON was validated"),
196 });
197 let mut bytes = serde_json::to_vec(&value).expect("inspection values serialize");
198 bytes.push(b'\n');
199 return bytes;
200 }
201 self.render_stream(&self.stream)
202 }
203
204 pub(crate) fn source_output_bytes(&self, stream: &SemanticStream<'a>) -> usize {
205 match stream {
206 SemanticStream::Entities(rows) => {
207 rows.iter().map(|&row| self.source_bytes(row).len()).sum()
208 }
209 SemanticStream::Types(rows) => rows
210 .iter()
211 .map(|row| {
212 row.ty
213 .as_ref()
214 .map_or("unknown", |ty| type_kind(&ty.kind))
215 .len()
216 + 1
217 })
218 .sum(),
219 SemanticStream::Instantiations(rows) => rows
220 .iter()
221 .map(|row| instantiation_name(row.instantiation).len() + 1)
222 .sum(),
223 SemanticStream::Inspection(_) => {
224 unreachable!("inspection renderer accounts its own leaves")
225 }
226 }
227 }
228
229 pub(crate) fn render_stream(&self, stream: &SemanticStream<'a>) -> Vec<u8> {
230 match stream {
231 SemanticStream::Inspection(result) => result.render(),
232 SemanticStream::Entities(entities) => entities
233 .iter()
234 .flat_map(|e| self.source_bytes(*e))
235 .copied()
236 .collect(),
237 SemanticStream::Types(rows) => rows
238 .iter()
239 .flat_map(|row| {
240 format!(
241 "{}\n",
242 row.ty.as_ref().map_or("unknown", |ty| type_kind(&ty.kind))
243 )
244 .into_bytes()
245 })
246 .collect(),
247 SemanticStream::Instantiations(rows) => rows
248 .iter()
249 .flat_map(|row| format!("{}\n", instantiation_name(row.instantiation)).into_bytes())
250 .collect(),
251 }
252 }
253
254 pub(crate) fn admit_program_json(
255 &self,
256 stream: &SemanticStream<'a>,
257 work: &mut Work,
258 range: &Range<usize>,
259 ) -> Result<(), QueryError> {
260 match stream {
261 SemanticStream::Inspection(value) => crate::inspection::admit_json(value, work, range)?,
262 SemanticStream::Entities(rows) => {
263 work.produce(1, range)?;
264 for &row in rows {
265 self.admit_subject_program_json(&SemanticSubject::Entity(row), work, range)?;
266 }
267 }
268 SemanticStream::Types(rows) => {
269 work.produce(1, range)?;
270 for row in rows {
271 let (units, bytes) = row.ty.as_ref().map_or((1, 0), type_allocation);
272 work.produce(units * 16 + 2, range)?;
273 work.spend(bytes + units * 64, range)?;
274 self.admit_subject_program_json(&row.subject, work, range)?;
275 }
276 }
277 SemanticStream::Instantiations(rows) => {
278 work.produce(1, range)?;
279 for row in rows {
280 self.admit_subject_program_json(&row.subject, work, range)?;
281 work.produce(4, range)?;
282 work.spend(row.reason.as_ref().map_or(0, String::len), range)?;
283 }
284 }
285 }
286 Ok(())
287 }
288
289 fn admit_subject_program_json(
290 &self,
291 subject: &SemanticSubject<'_>,
292 work: &mut Work,
293 range: &Range<usize>,
294 ) -> Result<(), QueryError> {
295 work.produce(36, range)?;
296 work.spend(
297 256 + self.model.files[self.subject_file(subject)]
298 .path
299 .as_os_str()
300 .len()
301 + self.subject_bytes(subject).len(),
302 range,
303 )?;
304 if let SemanticSubject::Entity(entity) = subject {
305 work.spend(self.name(*entity).len(), range)?;
306 if let SemanticEntity::Reference(id) = entity {
307 let reference = &self.bindings().unwrap().references[*id];
308 if let BindingResolution::Overloads(ids) | BindingResolution::Ambiguous(ids) =
309 &reference.resolution
310 {
311 work.produce(ids.len(), range)?;
312 }
313 if reference.kind == ReferenceKind::Callable
314 && let Some(callables) = self.callables()
315 {
316 for call in &callables.calls {
317 work.visit(range)?;
318 if call.file == reference.file
319 && call.location.range.start == reference.location.range.start
320 {
321 match &call.outcome {
322 CallOutcome::Ambiguous { candidates } => {
323 work.produce(candidates.len(), range)?
324 }
325 CallOutcome::Unsupported { candidates, reason } => {
326 work.produce(candidates.len(), range)?;
327 work.spend(reason.len(), range)?;
328 }
329 CallOutcome::NoMatch { reason }
330 | CallOutcome::Unresolved { reason } => {
331 work.spend(reason.len(), range)?
332 }
333 CallOutcome::Intrinsic { name, .. } => {
334 work.spend(name.len(), range)?
335 }
336 _ => {}
337 }
338 break;
339 }
340 }
341 }
342 }
343 }
344 Ok(())
345 }
346 fn subject_json(&self, subject: &SemanticSubject<'_>) -> Result<Value, QueryError> {
347 let file_id = self.subject_file(subject);
348 let file = &self.model.files[file_id];
349 let location = self.subject_location(subject);
350 let text = std::str::from_utf8(self.subject_bytes(subject)).map_err(|_| {
351 model_error(
352 location.clone(),
353 "text and JSON inspection require UTF-8 source text",
354 )
355 })?;
356 let mut value = json!({"file": file.path.to_string_lossy(), "file_id": file_id, "range": range_json(&location.range), "source_kind": source_kind(file.kind), "text": text});
357 match subject {
358 SemanticSubject::Node { node, .. } => {
359 value["kind"] = json!(kind_name(node.kind()));
360 }
361 SemanticSubject::Entity(entity) => {
362 value["name"] = json!(self.name(*entity));
363 match entity {
364 SemanticEntity::Declaration(id) => {
365 let declaration = &self.bindings().unwrap().declarations[id.0];
366 value["kind"] = json!("declaration");
367 value["declaration_id"] = json!(id.0);
368 value["role"] =
369 json!(format!("{:?}", declaration.role).to_ascii_lowercase());
370 value["syntax_range"] = range_json(
371 &(declaration.syntax_range.start + file.byte_offset
372 ..declaration.syntax_range.end + file.byte_offset),
373 );
374 }
375 SemanticEntity::Reference(id) => {
376 let reference = &self.bindings().unwrap().references[*id];
377 value["kind"] = json!("reference");
378 value["reference_id"] = json!(id);
379 value["reference_kind"] = json!(reference_kind(reference.kind));
380 value["binding"] = binding_json(&reference.resolution);
381 if let Some(callables) = self.callables()
382 && reference.kind == ReferenceKind::Callable
383 {
384 value["call"] = callables
385 .calls
386 .iter()
387 .find(|call| {
388 call.file == reference.file
389 && call.location.range.start
390 == reference.location.range.start
391 })
392 .map_or(Value::Null, |call| call_json(&call.outcome));
393 }
394 }
395 }
396 }
397 }
398 Ok(value)
399 }
400 fn validate_json(&self, work: &mut Work, range: &Range<usize>) -> Result<(), QueryError> {
401 let validate = |subject: &SemanticSubject<'_>| {
402 std::str::from_utf8(self.subject_bytes(subject))
403 .map(|_| ())
404 .map_err(|_| {
405 model_error(
406 self.subject_location(subject),
407 "text and JSON inspection require UTF-8 source text",
408 )
409 })
410 };
411 match &self.stream {
412 SemanticStream::Inspection(result) => {
413 crate::inspection::validate_json(result, work, range)?
414 }
415 SemanticStream::Entities(rows) => {
416 for entity in rows {
417 validate(&SemanticSubject::Entity(*entity))?;
418 }
419 }
420 SemanticStream::Types(rows) => {
421 for row in rows {
422 validate(&row.subject)?;
423 }
424 }
425 SemanticStream::Instantiations(rows) => {
426 for row in rows {
427 validate(&row.subject)?;
428 }
429 }
430 }
431 Ok(())
432 }
433
434 fn json_value(&self) -> Result<Value, QueryError> {
435 self.json_stream(&self.stream)
436 }
437
438 pub(crate) fn json_stream(&self, stream: &SemanticStream<'a>) -> Result<Value, QueryError> {
439 match stream {
440 SemanticStream::Inspection(result) => crate::inspection::json_value(result),
441 SemanticStream::Entities(entities) => entities
442 .iter()
443 .map(|e| self.subject_json(&SemanticSubject::Entity(*e)))
444 .collect::<Result<Vec<_>, _>>()
445 .map(Value::Array),
446 SemanticStream::Types(rows) => rows
447 .iter()
448 .map(|row| {
449 let mut value = self.subject_json(&row.subject)?;
450 value["type"] = row.ty.as_ref().map_or(Value::Null, type_json);
451 Ok(value)
452 })
453 .collect::<Result<Vec<_>, _>>()
454 .map(Value::Array),
455 SemanticStream::Instantiations(rows) => rows
456 .iter()
457 .map(|row| {
458 let mut value = self.subject_json(&row.subject)?;
459 value["instantiation"] = json!(instantiation_name(row.instantiation));
460 value["reason"] = json!(row.reason);
461 Ok(value)
462 })
463 .collect::<Result<Vec<_>, _>>()
464 .map(Value::Array),
465 }
466 }
467}
468
469pub(crate) fn requests_facts(stage: &Stage) -> bool {
470 matches!(
471 stage.kind,
472 StageKind::References
473 | StageKind::Declarations
474 | StageKind::Uses
475 | StageKind::TransitiveReferences(_)
476 | StageKind::ReferencedDeclarations
477 | StageKind::Types
478 | StageKind::Instantiations
479 ) || matches!(&stage.kind, StageKind::Filter(predicate) if predicate_facts(predicate))
480 || matches!(&stage.kind, StageKind::SharedFilter(predicate) if predicate.requires_model_facts())
481}
482pub(crate) fn predicate_facts(predicate: &Predicate) -> bool {
483 matches!(
484 &predicate.kind,
485 PredicateKind::Type(_) | PredicateKind::Instantiation(_) | PredicateKind::SourceKind(_)
486 )
487}
488
489pub(crate) fn prepare<'a>(
490 query: &Query,
491 input: &'a Input,
492 facts: Rc<ModelFacts<'a>>,
493 work: &mut Work,
494 limits: Limits,
495) -> Result<SemanticResult<'a>, QueryError> {
496 let model = facts.model();
497 let requesting = query.stages.iter().find(|s| requests_facts(s)).unwrap();
498 if let Some(error) = model.errors.first() {
499 return Err(model_error(error.location.clone(), &error.message));
500 }
501 if input.mode != FileMode::Model {
502 return Err(QueryError::query(
503 requesting.range.clone(),
504 "semantic inspection requires model-file mode (.mzn)",
505 ));
506 }
507 let root = model
508 .root_file
509 .and_then(|id| model.files.get(id))
510 .ok_or_else(|| {
511 QueryError::query(
512 requesting.range.clone(),
513 "semantic inspection requires a retained root file",
514 )
515 })?;
516 if input.syntax_offset != root.byte_offset
517 || input.bytes[input.syntax_offset..] != *root.source_bytes()
518 {
519 return Err(QueryError::input(
520 0..input.bytes.len().min(3),
521 "semantic input must exactly match the retained model root's original bytes, including its BOM",
522 ));
523 }
524 let selection = Selection {
525 input,
526 items: crate::collect_items(input, limits.collection, work, &query.range, true)?,
527 document: true,
528 };
529 let mut report = SemanticResult {
530 model,
531 facts,
532 bindings_requested: false,
533 callables_requested: false,
534 instantiations_requested: false,
535 body_callables: None,
536 reference_order: None,
537 stream: SemanticStream::Inspection(Box::new(QueryResult::Selection(selection))),
538 limitations: Vec::new(),
539 json: false,
540 incomplete_observation: None,
541 };
542 for limitation in &model.limitations {
543 report.limit(
544 limitation.location.clone(),
545 &limitation.message,
546 work,
547 requesting,
548 limits,
549 )?;
550 }
551 Ok(report)
552}
553
554impl<'a> SemanticResult<'a> {
555 pub(crate) fn evaluate_stage(
556 &mut self,
557 input: &'a Input,
558 stream: SemanticStream<'a>,
559 stage: &Stage,
560 work: &mut Work,
561 limits: Limits,
562 callable_references: &mut Vec<usize>,
563 ) -> Result<SemanticStream<'a>, QueryError> {
564 let model = self.model;
565 Ok(match &stage.kind {
566 StageKind::References => {
567 self.ensure_bindings(work, stage)?;
568 let subjects = subjects(stream, model, stage, limits, work)?;
569 SemanticStream::Entities(self.references(
570 &subjects,
571 work,
572 stage,
573 limits,
574 callable_references,
575 )?)
576 }
577 StageKind::Declarations => {
578 self.ensure_bindings(work, stage)?;
579 let subjects = subjects(stream, model, stage, limits, work)?;
580 SemanticStream::Entities(self.declarations(&subjects, work, stage, limits)?)
581 }
582 StageKind::Uses => {
583 self.ensure_bindings(work, stage)?;
584 let subjects = subjects(stream, model, stage, limits, work)?;
585 let declarations = self.declarations(&subjects, work, stage, limits)?;
586 SemanticStream::Entities(self.uses(&declarations, work, stage, limits)?)
587 }
588 StageKind::ReferencedDeclarations => {
589 self.ensure_bindings(work, stage)?;
590 let SemanticStream::Entities(declarations) = stream else {
591 return Err(type_error(
592 &stage.range,
593 "referenced_declarations requires declarations",
594 ));
595 };
596 SemanticStream::Entities(self.referenced_declarations(
597 &declarations,
598 work,
599 stage,
600 limits,
601 )?)
602 }
603 StageKind::TransitiveReferences(depth) => {
604 self.ensure_bindings(work, stage)?;
605 let subjects = subjects(stream, model, stage, limits, work)?;
606 let declarations = self.declarations(&subjects, work, stage, limits)?;
607 SemanticStream::Entities(self.transitive(
608 &declarations,
609 *depth,
610 work,
611 stage,
612 limits,
613 )?)
614 }
615 StageKind::Types => {
616 let subjects = subjects(stream, model, stage, limits, work)?;
617 let subjects = self.typed_subjects(subjects, work, stage, limits)?;
618 let mut rows = Vec::new();
619 for subject in subjects {
620 check_collection(rows.len(), limits.collection, &stage.range)?;
621 work.produce(1, &stage.range)?;
622 let ty = self.type_of(&subject, work, stage, limits)?;
623 rows.push(SemanticType { subject, ty });
624 }
625 SemanticStream::Types(rows)
626 }
627 StageKind::Instantiations => {
628 let subjects = subjects(stream, model, stage, limits, work)?;
629 let subjects = self.typed_subjects(subjects, work, stage, limits)?;
630 let mut rows = Vec::new();
631 for subject in subjects {
632 check_collection(rows.len(), limits.collection, &stage.range)?;
633 work.produce(1, &stage.range)?;
634 let (instantiation, reason) =
635 self.instantiation_of(&subject, work, stage, limits)?;
636 rows.push(SemanticInstantiation {
637 subject,
638 instantiation,
639 reason,
640 });
641 }
642 SemanticStream::Instantiations(rows)
643 }
644 StageKind::Filter(_)
645 | StageKind::Head(_)
646 | StageKind::Tail(_)
647 | StageKind::Reverse
648 | StageKind::Check { .. }
649 | StageKind::Count
650 | StageKind::Unique
651 | StageKind::Tally => unreachable!("the core evaluates common stages"),
652 StageKind::Names | StageKind::Text
653 if !matches!(stream, SemanticStream::Inspection(_)) =>
654 {
655 let subjects = subjects(stream, model, stage, limits, work)?;
656 let mut values = Vec::new();
657 for subject in subjects {
658 let names = if matches!(stage.kind, StageKind::Text) {
659 let location = self.subject_location(&subject);
660 vec![
661 std::str::from_utf8(self.subject_bytes(&subject)).map_err(|_| {
662 model_error(location, "text inspection requires UTF-8 source text")
663 })?,
664 ]
665 } else {
666 match &subject {
667 SemanticSubject::Entity(entity) => vec![self.name(*entity)],
668 SemanticSubject::Node { file, node, .. } => {
669 work.spend(node.children().len(), &stage.range)?;
670 crate::inspection::direct_names(&model.files[*file].parsed, node)
671 }
672 }
673 };
674 for name in names {
675 check_collection(values.len(), limits.collection, &stage.range)?;
676 work.produce(1, &stage.range)?;
677 work.spend(name.len().max(1), &stage.range)?;
678 values.push(name.to_owned());
679 }
680 }
681 SemanticStream::Inspection(Box::new(QueryResult::Strings(values)))
682 }
683 StageKind::Emit if !matches!(stream, SemanticStream::Inspection(_)) => stream,
684 StageKind::Json => {
685 self.json = true;
686 stream
687 }
688 _ => match stream {
689 SemanticStream::Inspection(result) => SemanticStream::Inspection(Box::new(
690 crate::evaluate_stage(input, Some(model), *result, stage, work, limits)?,
691 )),
692 _ => {
693 return Err(type_error(
694 &stage.range,
695 "stage does not accept this semantic stream",
696 ));
697 }
698 },
699 })
700 }
701
702 pub(crate) fn finish(
703 &mut self,
704 callable_references: Vec<usize>,
705 work: &mut Work,
706 requesting: &Stage,
707 range: &Range<usize>,
708 limits: Limits,
709 ) -> Result<(), QueryError> {
710 self.finish_reference_limitations(callable_references, work, requesting, limits)?;
711 self.charge_output(work, range, limits)?;
712 if self.json {
713 self.validate_json(work, range)?;
714 }
715 Ok(())
716 }
717}
718
719fn subjects<'a>(
720 stream: SemanticStream<'a>,
721 model: &ModelContext,
722 stage: &Stage,
723 limits: Limits,
724 work: &mut Work,
725) -> Result<Vec<SemanticSubject<'a>>, QueryError> {
726 let mut subjects = Vec::new();
727 match stream {
728 SemanticStream::Entities(rows) => {
729 for entity in rows {
730 check_collection(subjects.len(), limits.collection, &stage.range)?;
731 work.produce(1, &stage.range)?;
732 work.visit(&stage.range)?;
733 subjects.push(SemanticSubject::Entity(entity));
734 }
735 }
736 SemanticStream::Types(rows) => {
737 for row in rows {
738 work.visit(&stage.range)?;
739 subjects.push(row.subject);
740 }
741 }
742 SemanticStream::Instantiations(rows) => {
743 for row in rows {
744 work.visit(&stage.range)?;
745 subjects.push(row.subject);
746 }
747 }
748 SemanticStream::Inspection(result) => {
749 let nodes = crate::inspection::into_nodes(*result, &stage.range, work)?;
750 for selected in nodes.nodes {
751 work.visit(&stage.range)?;
752 check_collection(subjects.len(), limits.collection, &stage.range)?;
753 work.produce(1, &stage.range)?;
754 subjects.push(SemanticSubject::Node {
755 file: model.root_file.unwrap(),
756 node: selected.node,
757 location: model.files[model.root_file.unwrap()].location(selected.node.range()),
758 });
759 }
760 }
761 }
762 Ok(subjects)
763}
764
765pub(crate) fn admit_model_facts(
767 model: &ModelContext,
768 work: &mut Work,
769 range: &Range<usize>,
770) -> Result<(), QueryError> {
771 if let Some(error) = model.errors.first() {
772 return Err(model_error(error.location.clone(), &error.message));
773 }
774 for source in &model.files {
775 work.spend(source.parsed.tokens().len(), range)?;
776 work.visit(range)?;
777 let mut pending = vec![source.parsed.tree()];
778 while let Some(node) = pending.pop() {
779 for child in node.child_nodes() {
780 work.visit(range)?;
781 pending.push(child);
782 }
783 }
784 }
785 Ok(())
786}
787
788impl SemanticResult<'_> {
789 pub(crate) fn admit_fact_owner(
791 &mut self,
792 work: &mut Work,
793 range: &Range<usize>,
794 ) -> Result<(), QueryError> {
795 if !self.bindings_requested {
796 admit_model_facts(self.model, work, range)?;
797 self.facts.bindings();
798 self.bindings_requested = true;
799 }
800 Ok(())
801 }
802 fn ensure_bindings(&mut self, work: &mut Work, stage: &Stage) -> Result<(), QueryError> {
803 self.admit_fact_owner(work, &stage.range)
804 }
805 fn ensure_callables(&mut self, work: &mut Work, stage: &Stage) -> Result<(), QueryError> {
806 self.ensure_bindings(work, stage)?;
807 self.facts.source_callables();
808 self.callables_requested = true;
809 Ok(())
810 }
811 fn ensure_occurrence_callables(
812 &mut self,
813 subject: &SemanticSubject<'_>,
814 work: &mut Work,
815 stage: &Stage,
816 ) -> Result<(), QueryError> {
817 self.ensure_callables(work, stage)?;
818 let file = self.subject_file(subject);
819 if self.model.files[file].kind != SourceKind::StandardLibrary
820 || self.declared_subject(subject, work, stage)?.is_some()
821 {
822 return Ok(());
823 }
824 let location = self.subject_location(subject);
825 let facts = self.callables().unwrap();
826 for fact in &facts.expressions {
827 work.visit(&stage.range)?;
828 if fact.file == file && fact.location.range == location.range {
829 return Ok(());
830 }
831 }
832 if let SemanticSubject::Entity(SemanticEntity::Reference(id)) = subject {
833 let reference = &self.bindings().unwrap().references[*id];
834 if reference.kind == ReferenceKind::Callable {
835 for call in &facts.calls {
836 work.visit(&stage.range)?;
837 if call.file == file && call.location.range.start == location.range.start {
838 return Ok(());
839 }
840 }
841 }
842 }
843 let offset = self.model.files[file].byte_offset;
844 let mut owner = None;
845 for declaration in &self.bindings().unwrap().declarations {
846 work.visit(&stage.range)?;
847 if declaration.file == file
848 && matches!(
849 declaration.role,
850 zincite_lint::DeclarationRole::Function
851 | zincite_lint::DeclarationRole::Predicate
852 | zincite_lint::DeclarationRole::Test
853 | zincite_lint::DeclarationRole::Annotation
854 )
855 && declaration.syntax_range.start + offset <= location.range.start
856 && location.range.end <= declaration.syntax_range.end + offset
857 {
858 owner = Some(declaration.id);
859 break;
860 }
861 }
862 if let Some(owner) = owner {
863 self.body_callables = Some(self.facts.source_callable_body(facts, owner));
864 }
865 Ok(())
866 }
867 fn ensure_instantiations(&mut self, work: &mut Work, stage: &Stage) -> Result<(), QueryError> {
868 self.ensure_callables(work, stage)?;
869 self.facts.instantiations();
870 self.instantiations_requested = true;
871 Ok(())
872 }
873 fn owning_range(&self, subject: &SemanticSubject<'_>) -> Range<usize> {
874 match subject {
875 SemanticSubject::Entity(SemanticEntity::Declaration(id)) => {
876 let declaration = &self.bindings().unwrap().declarations[id.0];
877 let offset = self.model.files[declaration.file].byte_offset;
878 declaration.syntax_range.start + offset..declaration.syntax_range.end + offset
879 }
880 _ => self.subject_location(subject).range,
881 }
882 }
883 fn references(
884 &mut self,
885 subjects: &[SemanticSubject<'_>],
886 work: &mut Work,
887 stage: &Stage,
888 limits: Limits,
889 callable_references: &mut Vec<usize>,
890 ) -> Result<Vec<SemanticEntity>, QueryError> {
891 let mut rows = Vec::new();
892 for subject in subjects {
893 let file = self.subject_file(subject);
894 let region = self.owning_range(subject);
895 for id in 0..self.bindings().unwrap().references.len() {
896 work.visit(&stage.range)?;
897 let reference = &self.bindings().unwrap().references[id];
898 if reference.file == file && contains(®ion, &reference.location.range) {
899 check_collection(rows.len(), limits.collection, &stage.range)?;
900 work.produce(1, &stage.range)?;
901 rows.push(SemanticEntity::Reference(id));
902 if reference.kind == ReferenceKind::Callable {
903 work.spend(callable_references.len(), &stage.range)?;
907 if !callable_references.contains(&id) {
908 check_collection(
909 callable_references.len(),
910 limits.collection,
911 &stage.range,
912 )?;
913 callable_references.push(id);
914 }
915 } else if matches!(
916 reference.resolution,
917 BindingResolution::Unresolved | BindingResolution::Ambiguous(_)
918 ) {
919 self.limit(
920 reference.location.clone(),
921 format!(
922 "reference '{}' has an unresolved or ambiguous binding",
923 reference.name
924 ),
925 work,
926 stage,
927 limits,
928 )?;
929 }
930 }
931 }
932 }
933 Ok(rows)
934 }
935 fn finish_reference_limitations(
936 &mut self,
937 callable_references: Vec<usize>,
938 work: &mut Work,
939 stage: &Stage,
940 limits: Limits,
941 ) -> Result<(), QueryError> {
942 for id in callable_references {
943 work.visit(&stage.range)?;
944 if self.callables_requested {
945 self.target(id, work, stage, limits)?;
948 } else {
949 let reference = &self.bindings().unwrap().references[id];
950 if matches!(
951 reference.resolution,
952 BindingResolution::Unresolved | BindingResolution::Ambiguous(_)
953 ) {
954 self.limit(
955 reference.location.clone(),
956 format!(
957 "reference '{}' has an unresolved or ambiguous binding",
958 reference.name
959 ),
960 work,
961 stage,
962 limits,
963 )?;
964 }
965 }
966 }
967 Ok(())
968 }
969
970 fn declarations(
971 &mut self,
972 subjects: &[SemanticSubject<'_>],
973 work: &mut Work,
974 stage: &Stage,
975 limits: Limits,
976 ) -> Result<Vec<SemanticEntity>, QueryError> {
977 let mut rows = Vec::new();
978 for subject in subjects {
979 match subject {
980 SemanticSubject::Entity(SemanticEntity::Declaration(id)) => {
981 check_collection(rows.len(), limits.collection, &stage.range)?;
982 work.produce(1, &stage.range)?;
983 work.visit(&stage.range)?;
984 rows.push(SemanticEntity::Declaration(*id));
985 }
986 SemanticSubject::Entity(SemanticEntity::Reference(id)) => {
987 if let Some(target) = self.target(*id, work, stage, limits)? {
988 check_collection(rows.len(), limits.collection, &stage.range)?;
989 work.produce(1, &stage.range)?;
990 rows.push(SemanticEntity::Declaration(target));
991 }
992 }
993 SemanticSubject::Node { file, node, .. } => {
994 for declaration in &self.bindings().unwrap().declarations {
995 work.visit(&stage.range)?;
996 if declaration.file == *file && declaration.syntax_range == node.range() {
997 check_collection(rows.len(), limits.collection, &stage.range)?;
998 work.produce(1, &stage.range)?;
999 rows.push(SemanticEntity::Declaration(declaration.id));
1000 }
1001 }
1002 }
1003 }
1004 }
1005 Ok(rows)
1006 }
1007 fn endpoint(
1008 &mut self,
1009 id: usize,
1010 work: &mut Work,
1011 stage: &Stage,
1012 _limits: Limits,
1013 ) -> Result<ReferenceEndpoint, QueryError> {
1014 work.visit(&stage.range)?;
1015 if self.bindings().unwrap().references[id].kind == ReferenceKind::Callable {
1016 self.ensure_occurrence_callables(
1017 &SemanticSubject::Entity(SemanticEntity::Reference(id)),
1018 work,
1019 stage,
1020 )?;
1021 }
1022 let reference = &self.bindings().unwrap().references[id];
1023 let location = reference.location.clone();
1024 let mut reason = format!(
1025 "reference '{}' has no proven declaration target",
1026 reference.name
1027 );
1028 if reference.kind == ReferenceKind::Callable {
1029 for call in &self.callables().unwrap().calls {
1030 work.visit(&stage.range)?;
1031 if call.file != reference.file || call.location.range.start != location.range.start
1032 {
1033 continue;
1034 }
1035 match &call.outcome {
1036 CallOutcome::Resolved { declaration, .. } => {
1037 return Ok(ReferenceEndpoint::Declaration(*declaration));
1038 }
1039 CallOutcome::Intrinsic { .. } => return Ok(ReferenceEndpoint::Intrinsic),
1040 CallOutcome::NoMatch { reason: r }
1041 | CallOutcome::Unresolved { reason: r }
1042 | CallOutcome::Unsupported { reason: r, .. } => reason = r.clone(),
1043 CallOutcome::Ambiguous { .. } => {
1044 reason = format!("call '{}' is ambiguous", reference.name)
1045 }
1046 }
1047 break;
1048 }
1049 } else if let BindingResolution::Resolved(declaration) = reference.resolution {
1050 return Ok(ReferenceEndpoint::Declaration(declaration));
1051 }
1052 Ok(ReferenceEndpoint::Uncertain(location, reason))
1053 }
1054 fn target(
1055 &mut self,
1056 id: usize,
1057 work: &mut Work,
1058 stage: &Stage,
1059 limits: Limits,
1060 ) -> Result<Option<DeclarationId>, QueryError> {
1061 match self.endpoint(id, work, stage, limits)? {
1062 ReferenceEndpoint::Declaration(id) => Ok(Some(id)),
1063 ReferenceEndpoint::Intrinsic => Ok(None),
1064 ReferenceEndpoint::Uncertain(location, reason) => {
1065 if self.incomplete_observation.is_none() {
1066 work.spend(
1067 location.path.as_os_str().len() + reason.len() + 1,
1068 &stage.range,
1069 )?;
1070 work.produce(1, &stage.range)?;
1071 self.incomplete_observation = Some(std::sync::Arc::new(QueryError {
1072 range: location.range.clone(),
1073 location: crate::ErrorLocation::Model(location.clone()),
1074 message: reason.clone(),
1075 }));
1076 }
1077 self.limit(location, reason, work, stage, limits)?;
1078 Ok(None)
1079 }
1080 }
1081 }
1082
1083 pub(crate) fn complete_targets(
1086 &mut self,
1087 id: DeclarationId,
1088 work: &mut Work,
1089 range: &Range<usize>,
1090 limits: Limits,
1091 ) -> Result<Vec<SemanticEntity>, QueryError> {
1092 let stage = Stage {
1093 kind: StageKind::ReferencedDeclarations,
1094 range: range.clone(),
1095 };
1096 self.ensure_bindings(work, &stage)?;
1097 let declaration = self
1098 .bindings()
1099 .unwrap()
1100 .declarations
1101 .get(id.0)
1102 .ok_or_else(|| type_error(range, "unavailable declaration identity"))?;
1103 let file = declaration.file;
1104 let offset = self.model.files[file].byte_offset;
1105 let region = declaration.syntax_range.start + offset..declaration.syntax_range.end + offset;
1106 if self.reference_order.is_none() {
1107 work.produce(self.bindings().unwrap().references.len(), range)?;
1108 self.reference_order = Some(self.ordered_references(work, &stage, limits)?);
1109 }
1110 let references = &self.bindings().unwrap().references;
1111 let order = self.reference_order.as_ref().unwrap();
1112 work.spend(order.len().max(1).ilog2() as usize + 1, range)?;
1113 let first = order.partition_point(|&i| {
1114 (references[i].file, references[i].location.range.start) < (file, region.start)
1115 });
1116 let mut selected = HashSet::new();
1117 let mut rows = Vec::new();
1118 let mut index = first;
1119 while let Some(&reference) = self.reference_order.as_ref().unwrap().get(index) {
1120 index += 1;
1121 work.visit(range)?;
1122 let occurrence = &self.bindings().unwrap().references[reference];
1123 if occurrence.file != file || occurrence.location.range.start >= region.end {
1124 break;
1125 }
1126 if !contains(®ion, &occurrence.location.range) {
1127 continue;
1128 }
1129 match self.endpoint(reference, work, &stage, limits)? {
1130 ReferenceEndpoint::Declaration(target) => {
1131 if selected.contains(&target.0) {
1132 continue;
1133 }
1134 check_collection(rows.len(), limits.collection, range)?;
1135 work.produce(2, range)?;
1136 selected.insert(target.0);
1137 rows.push(SemanticEntity::Declaration(target));
1138 }
1139 ReferenceEndpoint::Intrinsic => {}
1140 ReferenceEndpoint::Uncertain(location, reason) => {
1141 return Err(model_error(
1142 location,
1143 format!("reference_info cannot provide complete adjacency: {reason}"),
1144 ));
1145 }
1146 }
1147 }
1148 Ok(rows)
1149 }
1150 fn uses(
1151 &mut self,
1152 declarations: &[SemanticEntity],
1153 work: &mut Work,
1154 stage: &Stage,
1155 limits: Limits,
1156 ) -> Result<Vec<SemanticEntity>, QueryError> {
1157 let mut rows = Vec::new();
1158 let mut selected = HashSet::new();
1159 let mut names = HashSet::new();
1160 for declaration in declarations {
1161 let SemanticEntity::Declaration(id) = declaration else {
1162 unreachable!()
1163 };
1164 work.visit(&stage.range)?;
1165 check_collection(selected.len(), limits.collection, &stage.range)?;
1166 work.produce(1, &stage.range)?;
1167 selected.insert(id.0);
1168 let name = &self.bindings().unwrap().declarations[id.0].name;
1169 work.spend(name.len(), &stage.range)?;
1170 check_collection(names.len(), limits.collection, &stage.range)?;
1171 work.produce(1, &stage.range)?;
1172 names.insert(name.clone());
1173 }
1174 let mut targets = Vec::new();
1176 for id in 0..self.bindings().unwrap().references.len() {
1177 work.visit(&stage.range)?;
1178 let reference = &self.bindings().unwrap().references[id];
1179 if !selected.is_empty() {
1180 let relevant = match &reference.resolution {
1183 BindingResolution::Resolved(id) => selected.contains(&id.0),
1184 BindingResolution::Overloads(ids) | BindingResolution::Ambiguous(ids) => {
1185 work.spend(ids.len(), &stage.range)?;
1186 ids.iter().any(|id| selected.contains(&id.0))
1187 }
1188 BindingResolution::Unresolved => {
1189 work.spend(reference.name.len(), &stage.range)?;
1190 names.contains(&reference.name)
1191 }
1192 };
1193 if !relevant {
1194 continue;
1195 }
1196 }
1197 check_collection(targets.len(), limits.collection, &stage.range)?;
1198 work.produce(1, &stage.range)?;
1199 targets.push((id, self.target(id, work, stage, limits)?));
1200 }
1201 for declaration in declarations {
1202 let SemanticEntity::Declaration(declaration) = declaration else {
1203 unreachable!()
1204 };
1205 for (id, target) in &targets {
1206 work.visit(&stage.range)?;
1207 if *target == Some(*declaration) {
1208 check_collection(rows.len(), limits.collection, &stage.range)?;
1209 work.produce(1, &stage.range)?;
1210 rows.push(SemanticEntity::Reference(*id));
1211 }
1212 }
1213 }
1214 Ok(rows)
1215 }
1216 fn ordered_references(
1217 &self,
1218 work: &mut Work,
1219 stage: &Stage,
1220 limits: Limits,
1221 ) -> Result<Vec<usize>, QueryError> {
1222 let references = &self.bindings().unwrap().references;
1223 work.spend(
1224 references
1225 .len()
1226 .saturating_mul(references.len().max(1).ilog2() as usize + 1),
1227 &stage.range,
1228 )?;
1229 if references.len() > limits.collection {
1230 return Err(type_error(&stage.range, "query collection limit exceeded"));
1231 }
1232 let mut order: Vec<_> = (0..references.len()).collect();
1233 order.sort_by_key(|&id| {
1234 let r = &references[id];
1235 (
1236 r.file,
1237 r.location.range.start,
1238 r.location.range.end,
1239 reference_order(r.kind),
1240 )
1241 });
1242 Ok(order)
1243 }
1244
1245 fn referenced_declarations(
1246 &mut self,
1247 declarations: &[SemanticEntity],
1248 work: &mut Work,
1249 stage: &Stage,
1250 limits: Limits,
1251 ) -> Result<Vec<SemanticEntity>, QueryError> {
1252 let order = self.ordered_references(work, stage, limits)?;
1253 let mut rows = Vec::new();
1254 for declaration in declarations {
1255 let SemanticEntity::Declaration(id) = declaration else {
1256 return Err(type_error(
1257 &stage.range,
1258 "referenced_declarations requires declarations",
1259 ));
1260 };
1261 work.visit(&stage.range)?;
1262 let declaration = &self.bindings().unwrap().declarations[id.0];
1263 let file = declaration.file;
1264 let offset = self.model.files[file].byte_offset;
1265 let region =
1266 declaration.syntax_range.start + offset..declaration.syntax_range.end + offset;
1267 let mut selected = Vec::new();
1268 for &reference in &order {
1269 work.visit(&stage.range)?;
1270 let occurrence = &self.bindings().unwrap().references[reference];
1271 if occurrence.file != file || !contains(®ion, &occurrence.location.range) {
1272 continue;
1273 }
1274 if let Some(target) = self.target(reference, work, stage, limits)? {
1275 let mut repeated = false;
1276 for previous in &selected {
1277 work.visit(&stage.range)?;
1278 if *previous == target {
1279 repeated = true;
1280 break;
1281 }
1282 }
1283 if repeated {
1284 continue;
1285 }
1286 check_collection(selected.len(), limits.collection, &stage.range)?;
1287 check_collection(rows.len(), limits.collection, &stage.range)?;
1288 work.produce(2, &stage.range)?;
1289 selected.push(target);
1290 rows.push(SemanticEntity::Declaration(target));
1291 }
1292 }
1293 }
1294 Ok(rows)
1295 }
1296
1297 fn transitive(
1298 &mut self,
1299 declarations: &[SemanticEntity],
1300 depth: usize,
1301 work: &mut Work,
1302 stage: &Stage,
1303 limits: Limits,
1304 ) -> Result<Vec<SemanticEntity>, QueryError> {
1305 if depth == 0 {
1306 return Ok(Vec::new());
1307 }
1308 let mut frontier = Vec::new();
1309 let mut visited = HashSet::new();
1310 for entity in declarations {
1311 let SemanticEntity::Declaration(id) = entity else {
1312 unreachable!()
1313 };
1314 work.visit(&stage.range)?;
1315 if !visited.contains(&id.0) {
1316 check_collection(visited.len(), limits.collection, &stage.range)?;
1317 visited.insert(id.0);
1318 frontier.push(*id);
1319 }
1320 }
1321 let order = self.ordered_references(work, stage, limits)?;
1322 let mut emitted = HashSet::new();
1323 let mut rows = Vec::new();
1324 for _ in 0..depth {
1325 if frontier.is_empty() {
1326 break;
1327 }
1328 let mut next = Vec::new();
1329 for declaration in frontier {
1330 work.visit(&stage.range)?;
1331 let declaration = &self.bindings().unwrap().declarations[declaration.0];
1332 let file = declaration.file;
1333 let offset = self.model.files[file].byte_offset;
1334 let region =
1335 declaration.syntax_range.start + offset..declaration.syntax_range.end + offset;
1336 for &id in &order {
1337 work.visit(&stage.range)?;
1338 let reference = &self.bindings().unwrap().references[id];
1339 if reference.file != file || !contains(®ion, &reference.location.range) {
1340 continue;
1341 }
1342 let identity = (
1343 file,
1344 reference.location.range.start,
1345 reference.location.range.end,
1346 reference_order(reference.kind),
1347 );
1348 if !emitted.contains(&identity) {
1349 check_collection(rows.len(), limits.collection, &stage.range)?;
1350 work.produce(1, &stage.range)?;
1351 emitted.insert(identity);
1352 rows.push(SemanticEntity::Reference(id));
1353 }
1354 if let Some(target) = self.target(id, work, stage, limits)?
1355 && !visited.contains(&target.0)
1356 {
1357 check_collection(visited.len(), limits.collection, &stage.range)?;
1358 visited.insert(target.0);
1359 next.push(target);
1360 }
1361 }
1362 }
1363 frontier = next;
1364 }
1365 Ok(rows)
1366 }
1367
1368 fn typed_subjects<'a>(
1369 &mut self,
1370 subjects: Vec<SemanticSubject<'a>>,
1371 work: &mut Work,
1372 stage: &Stage,
1373 limits: Limits,
1374 ) -> Result<Vec<SemanticSubject<'a>>, QueryError> {
1375 self.ensure_bindings(work, stage)?;
1376 let mut rows = Vec::new();
1377 for subject in subjects {
1378 let before = rows.len();
1379 if let SemanticSubject::Node { file, node, .. } = &subject {
1380 for declaration in &self.bindings().unwrap().declarations {
1381 work.visit(&stage.range)?;
1382 if declaration.file == *file && declaration.syntax_range == node.range() {
1383 check_collection(rows.len(), limits.collection, &stage.range)?;
1384 work.produce(1, &stage.range)?;
1385 rows.push(SemanticSubject::Entity(SemanticEntity::Declaration(
1386 declaration.id,
1387 )));
1388 }
1389 }
1390 }
1391 if rows.len() == before {
1392 check_collection(rows.len(), limits.collection, &stage.range)?;
1393 work.produce(1, &stage.range)?;
1394 rows.push(subject);
1395 }
1396 }
1397 Ok(rows)
1398 }
1399
1400 fn type_of(
1401 &mut self,
1402 subject: &SemanticSubject<'_>,
1403 work: &mut Work,
1404 stage: &Stage,
1405 limits: Limits,
1406 ) -> Result<Option<TypeInst>, QueryError> {
1407 self.ensure_occurrence_callables(subject, work, stage)?;
1408 let declaration = self.declared_subject(subject, work, stage)?;
1409 let facts = self.callables().unwrap();
1410 let mut ty = None;
1411 if let Some(id) = declaration {
1412 for fact in &facts.declarations {
1413 work.visit(&stage.range)?;
1414 if fact.declaration == id {
1415 ty = Some(&fact.ty);
1416 break;
1417 }
1418 }
1419 } else {
1420 let file = self.subject_file(subject);
1421 let location = self.subject_location(subject);
1422 for fact in &facts.expressions {
1424 work.visit(&stage.range)?;
1425 if fact.file == file && fact.location.range == location.range {
1426 ty = Some(&fact.ty);
1427 break;
1428 }
1429 }
1430 if ty.is_none()
1431 && let SemanticSubject::Entity(SemanticEntity::Reference(id)) = subject
1432 && self.bindings().unwrap().references[*id].kind == ReferenceKind::Callable
1433 {
1434 for fact in &facts.calls {
1435 work.visit(&stage.range)?;
1436 if fact.file == file && fact.location.range.start == location.range.start {
1437 ty = match &fact.outcome {
1438 CallOutcome::Resolved { return_type, .. }
1439 | CallOutcome::Intrinsic { return_type, .. } => Some(return_type),
1440 _ => None,
1441 };
1442 break;
1443 }
1444 }
1445 }
1446 }
1447 let reason = if let Some(ty) = ty {
1448 type_unknown(ty, work, &stage.range, limits)?
1449 } else {
1450 Some("type fact unavailable for this exact occurrence".to_owned())
1451 };
1452 if work.budget.remaining_results().is_some()
1453 && let Some(ty) = ty
1454 {
1455 let (units, bytes) = type_allocation(ty);
1456 work.produce(units, &stage.range)?;
1457 work.spend(bytes, &stage.range)?;
1458 }
1459 let ty = ty.cloned();
1460 if let Some(reason) = reason {
1461 self.limit(self.subject_location(subject), reason, work, stage, limits)?;
1462 }
1463 Ok(ty)
1464 }
1465
1466 fn declared_subject(
1467 &self,
1468 subject: &SemanticSubject<'_>,
1469 work: &mut Work,
1470 stage: &Stage,
1471 ) -> Result<Option<DeclarationId>, QueryError> {
1472 match subject {
1473 SemanticSubject::Entity(SemanticEntity::Declaration(id)) => Ok(Some(*id)),
1474 SemanticSubject::Node { file, node, .. } => {
1475 for declaration in &self.bindings().unwrap().declarations {
1478 work.visit(&stage.range)?;
1479 if declaration.file == *file && declaration.syntax_range == node.range() {
1480 return Ok(Some(declaration.id));
1481 }
1482 }
1483 Ok(None)
1484 }
1485 _ => Ok(None),
1486 }
1487 }
1488
1489 fn instantiation_of(
1490 &mut self,
1491 subject: &SemanticSubject<'_>,
1492 work: &mut Work,
1493 stage: &Stage,
1494 limits: Limits,
1495 ) -> Result<(Instantiation, Option<String>), QueryError> {
1496 let mut outcome = (
1497 Instantiation::Unknown,
1498 Some("instantiation fact unavailable for this exact occurrence".to_owned()),
1499 );
1500 self.ensure_bindings(work, stage)?;
1501 if let Some(id) = self.declared_subject(subject, work, stage)? {
1502 work.visit(&stage.range)?;
1503 let instantiation = self.bindings().unwrap().declarations[id.0].instantiation;
1504 outcome = (
1505 instantiation,
1506 (instantiation == Instantiation::Unknown)
1507 .then(|| "declared instantiation is unknown".to_owned()),
1508 );
1509 } else {
1510 self.ensure_occurrence_callables(subject, work, stage)?;
1511 self.ensure_instantiations(work, stage)?;
1512 let location = self.subject_location(subject);
1513 let file = self.subject_file(subject);
1514 for fact in &self.instantiation_facts().unwrap().expressions {
1515 work.visit(&stage.range)?;
1516 if fact.file == file && fact.location.range == location.range {
1517 outcome = (fact.instantiation, fact.reason.clone());
1518 break;
1519 }
1520 }
1521 if outcome.0 == Instantiation::Unknown
1522 && self.model.files[file].kind == SourceKind::StandardLibrary
1523 {
1524 for fact in &self.callables().unwrap().expressions {
1527 work.visit(&stage.range)?;
1528 if fact.file == file
1529 && fact.location.range == location.range
1530 && fact.ty.instantiation != Instantiation::Unknown
1531 {
1532 outcome = (fact.ty.instantiation, None);
1533 break;
1534 }
1535 }
1536 }
1537 if outcome.0 == Instantiation::Unknown
1538 && let SemanticSubject::Entity(SemanticEntity::Reference(id)) = subject
1539 && self.bindings().unwrap().references[*id].kind == ReferenceKind::Callable
1540 {
1541 for fact in &self.callables().unwrap().calls {
1542 work.visit(&stage.range)?;
1543 if fact.file == file && fact.location.range.start == location.range.start {
1544 match &fact.outcome {
1545 CallOutcome::Resolved { return_type, .. }
1546 | CallOutcome::Intrinsic { return_type, .. } => {
1547 outcome = (
1548 return_type.instantiation,
1549 (return_type.instantiation == Instantiation::Unknown)
1550 .then(|| "call return instantiation is unknown".to_owned()),
1551 );
1552 }
1553 _ => {}
1554 }
1555 break;
1556 }
1557 }
1558 }
1559 }
1560 if let Some(reason) = &outcome.1 {
1561 self.limit(self.subject_location(subject), reason, work, stage, limits)?;
1562 }
1563 Ok(outcome)
1564 }
1565
1566 pub(crate) fn guard_leaf(
1567 &mut self,
1568 predicate: &Predicate,
1569 subject: &SemanticSubject<'_>,
1570 work: &mut Work,
1571 stage: &Stage,
1572 limits: Limits,
1573 ) -> Result<(Truth, Option<SourceDiagnostic>), QueryError> {
1574 let truth = self.predicate_leaf(predicate, subject, work, stage, limits)?;
1575 let diagnostic = if truth == Truth::Unknown {
1576 let location = match subject {
1577 SemanticSubject::Entity(entity) => self.location(*entity),
1578 SemanticSubject::Node { location, .. } => location,
1579 };
1580 let mut existing = None;
1581 for diagnostic in self.limitations.iter().rev() {
1582 work.visit(&predicate.range)?;
1583 if diagnostic.location == *location {
1584 existing = Some(diagnostic);
1585 break;
1586 }
1587 }
1588 let message = existing.map_or("semantic guard fact is unknown", |d| d.message.as_str());
1589 work.spend(
1590 location.path.as_os_str().len() + message.len() + 1,
1591 &predicate.range,
1592 )?;
1593 work.produce(1, &predicate.range)?;
1594 Some(SourceDiagnostic {
1595 location: location.clone(),
1596 message: message.to_owned(),
1597 })
1598 } else {
1599 None
1600 };
1601 Ok((truth, diagnostic))
1602 }
1603 pub(crate) fn predicate_leaf(
1604 &mut self,
1605 predicate: &Predicate,
1606 subject: &SemanticSubject<'_>,
1607 work: &mut Work,
1608 stage: &Stage,
1609 limits: Limits,
1610 ) -> Result<Truth, QueryError> {
1611 Ok(match &predicate.kind {
1612 PredicateKind::Type(expected) => match self.type_of(subject, work, stage, limits)? {
1613 Some(ty) if type_unknown(&ty, work, &predicate.range, limits)?.is_none() => {
1614 Truth::from(type_kind(&ty.kind) == expected)
1615 }
1616 _ => Truth::Unknown,
1617 },
1618 PredicateKind::Instantiation(expected) => {
1619 let (instantiation, _) = self.instantiation_of(subject, work, stage, limits)?;
1620 if instantiation == Instantiation::Unknown {
1621 Truth::Unknown
1622 } else {
1623 Truth::from(instantiation_name(instantiation) == expected)
1624 }
1625 }
1626 PredicateKind::SourceKind(expected) => Truth::from(
1627 source_kind(self.model.files[self.subject_file(subject)].kind) == expected,
1628 ),
1629 PredicateKind::Name(expected) => match subject {
1630 SemanticSubject::Entity(entity) => {
1631 Truth::from(self.name(*entity) == crate::identifier_identity(expected))
1632 }
1633 SemanticSubject::Node { file, node, .. } => {
1634 work.spend(node.children().len(), &predicate.range)?;
1635 Truth::from(
1636 crate::inspection::direct_names(&self.model.files[*file].parsed, node)
1637 .first()
1638 .copied()
1639 == Some(crate::identifier_identity(expected)),
1640 )
1641 }
1642 },
1643 PredicateKind::Kind(expected) => match subject {
1644 SemanticSubject::Entity(SemanticEntity::Reference(_)) => {
1645 Truth::from(expected == "reference")
1646 }
1647 SemanticSubject::Entity(SemanticEntity::Declaration(_)) => {
1648 Truth::from(expected == "declaration")
1649 }
1650 SemanticSubject::Node { node, .. } => Truth::from(
1651 kind_name(node.kind()) == *expected
1652 || crate::ItemKind::parse(expected)
1653 .is_some_and(|kind| kind.as_str() == item_kind_name(node.kind())),
1654 ),
1655 },
1656 })
1657 }
1658 fn charge_subject_json(
1659 &self,
1660 subject: &SemanticSubject<'_>,
1661 work: &mut Work,
1662 range: &Range<usize>,
1663 ) -> Result<(), QueryError> {
1664 if !self.json {
1665 return Ok(());
1666 }
1667 let file = &self.model.files[self.subject_file(subject)];
1668 work.spend(file.path.as_os_str().len(), range)?;
1669 if let SemanticSubject::Entity(entity) = subject {
1670 work.spend(self.name(*entity).len(), range)?;
1671 if let SemanticEntity::Reference(id) = entity {
1672 let reference = &self.bindings().unwrap().references[*id];
1673 if let BindingResolution::Overloads(ids) | BindingResolution::Ambiguous(ids) =
1674 &reference.resolution
1675 {
1676 work.spend(ids.len(), range)?;
1677 }
1678 if reference.kind == ReferenceKind::Callable
1679 && let Some(callables) = self.callables()
1680 {
1681 for call in &callables.calls {
1682 work.visit(range)?;
1683 if call.file == reference.file
1684 && call.location.range.start == reference.location.range.start
1685 {
1686 match &call.outcome {
1687 CallOutcome::Ambiguous { candidates }
1688 | CallOutcome::Unsupported { candidates, .. } => {
1689 work.spend(candidates.len(), range)?
1690 }
1691 _ => {}
1692 }
1693 break;
1694 }
1695 }
1696 }
1697 }
1698 }
1699 Ok(())
1700 }
1701
1702 fn charge_output(
1703 &self,
1704 work: &mut Work,
1705 range: &Range<usize>,
1706 limits: Limits,
1707 ) -> Result<(), QueryError> {
1708 if self.json {
1709 for limitation in &self.limitations {
1710 work.visit(range)?;
1711 work.spend(
1712 limitation.location.path.as_os_str().len() + limitation.message.len(),
1713 range,
1714 )?;
1715 }
1716 }
1717 match &self.stream {
1718 SemanticStream::Inspection(result) => match result.as_ref() {
1719 QueryResult::Selection(selection) => {
1720 for item in &selection.items {
1721 work.spend(item.range.len().max(1), range)?;
1722 if self.json {
1723 work.spend(selection.input.file().len(), range)?;
1724 }
1725 }
1726 }
1727 QueryResult::Nodes(selection) => {
1728 for node in &selection.nodes {
1729 work.spend(node.range.len().max(1), range)?;
1730 if self.json {
1731 work.spend(selection.input.file().len(), range)?;
1732 }
1733 }
1734 }
1735 QueryResult::Strings(values) => {
1736 for value in values {
1737 work.spend(value.len().max(1), range)?;
1738 }
1739 }
1740 QueryResult::Tally(values) => {
1741 for (value, _) in values {
1742 work.spend(value.len().max(1), range)?;
1743 }
1744 }
1745 QueryResult::Count(_) => {}
1746 QueryResult::Literals(selection) => {
1747 for value in selection.values() {
1748 work.spend(value.range.len(), range)?;
1749 }
1750 }
1751 _ => {
1752 return Err(type_error(
1753 range,
1754 "semantic inspection cannot produce an edit candidate",
1755 ));
1756 }
1757 },
1758 SemanticStream::Entities(rows) => {
1759 for entity in rows {
1760 work.spend(self.source_bytes(*entity).len().max(1), range)?;
1761 self.charge_subject_json(&SemanticSubject::Entity(*entity), work, range)?;
1762 }
1763 }
1764 SemanticStream::Types(rows) => {
1765 for row in rows {
1766 work.spend(self.subject_bytes(&row.subject).len().max(1), range)?;
1767 self.charge_subject_json(&row.subject, work, range)?;
1768 if let Some(ty) = &row.ty {
1769 type_unknown(ty, work, range, limits)?;
1770 }
1771 }
1772 }
1773 SemanticStream::Instantiations(rows) => {
1774 for row in rows {
1775 work.spend(self.subject_bytes(&row.subject).len().max(1), range)?;
1776 self.charge_subject_json(&row.subject, work, range)?;
1777 }
1778 }
1779 }
1780 Ok(())
1781 }
1782}
1783
1784#[derive(Clone, Copy, PartialEq, Eq)]
1785pub(crate) enum Truth {
1786 True,
1787 False,
1788 Unknown,
1789}
1790impl Truth {
1791 fn from(value: bool) -> Self {
1792 if value { Self::True } else { Self::False }
1793 }
1794}
1795fn item_kind_name(kind: zincite_syntax::NodeKind) -> &'static str {
1796 use zincite_syntax::NodeKind::*;
1797 match kind {
1798 Assignment => "assignment",
1799 Declaration => "declaration",
1800 EnumDeclaration => "enum",
1801 TypeAlias => "type_alias",
1802 FunctionDeclaration => "function",
1803 PredicateDeclaration => "predicate",
1804 TestDeclaration => "test",
1805 AnnotationDeclaration => "annotation",
1806 Constraint => "constraint",
1807 Include => "include",
1808 Output => "output",
1809 Solve | SolveMinimize | SolveMaximize => "solve",
1810 _ => "",
1811 }
1812}
1813fn model_error(location: SourceLocation, message: impl Into<String>) -> QueryError {
1814 QueryError {
1815 range: location.range.clone(),
1816 location: ErrorLocation::Model(location),
1817 message: message.into(),
1818 }
1819}
1820fn contains(region: &Range<usize>, range: &Range<usize>) -> bool {
1821 region.start <= range.start && range.end <= region.end
1822}
1823fn reference_order(kind: ReferenceKind) -> u8 {
1824 match kind {
1825 ReferenceKind::Value => 0,
1826 ReferenceKind::Callable => 1,
1827 ReferenceKind::Type => 2,
1828 }
1829}
1830fn reference_kind(kind: ReferenceKind) -> &'static str {
1831 match kind {
1832 ReferenceKind::Value => "value",
1833 ReferenceKind::Callable => "callable",
1834 ReferenceKind::Type => "type",
1835 }
1836}
1837fn source_kind(kind: SourceKind) -> &'static str {
1838 match kind {
1839 SourceKind::User => "user",
1840 SourceKind::StandardLibrary => "standard_library",
1841 }
1842}
1843fn instantiation_name(instantiation: Instantiation) -> &'static str {
1844 match instantiation {
1845 Instantiation::Parameter => "par",
1846 Instantiation::Decision => "var",
1847 Instantiation::Unknown => "unknown",
1848 }
1849}
1850pub(crate) fn known_type_kind(name: &str) -> bool {
1851 matches!(
1852 name,
1853 "bool"
1854 | "int"
1855 | "float"
1856 | "string"
1857 | "annotation"
1858 | "enum"
1859 | "set"
1860 | "array"
1861 | "tuple"
1862 | "record"
1863 | "bottom"
1864 )
1865}
1866fn type_kind(kind: &TypeKind) -> &'static str {
1867 match kind {
1868 TypeKind::Bool => "bool",
1869 TypeKind::Int => "int",
1870 TypeKind::Float => "float",
1871 TypeKind::String => "string",
1872 TypeKind::Annotation => "annotation",
1873 TypeKind::Enum(_) => "enum",
1874 TypeKind::Set(_) => "set",
1875 TypeKind::Array { .. } => "array",
1876 TypeKind::Tuple(_) => "tuple",
1877 TypeKind::Record(_) => "record",
1878 TypeKind::Bottom => "bottom",
1879 TypeKind::Variable { .. } => "variable",
1880 TypeKind::Unknown(_) => "unknown",
1881 }
1882}
1883fn type_unknown(
1884 ty: &TypeInst,
1885 work: &mut Work,
1886 range: &Range<usize>,
1887 limits: Limits,
1888) -> Result<Option<String>, QueryError> {
1889 check_collection(0, limits.collection, range)?;
1890 let mut pending = vec![(ty, 0)];
1891 let mut reason = None;
1892 while let Some((ty, depth)) = pending.pop() {
1893 work.visit(range)?;
1894 if depth > limits.nesting {
1895 return Err(type_error(range, "query type nesting limit exceeded"));
1896 }
1897 let unknown = match &ty.kind {
1898 TypeKind::Unknown(message) => {
1899 work.spend(message.len(), range)?;
1900 Some(message.clone())
1901 }
1902 TypeKind::Variable { name, .. } => {
1903 work.spend(name.len(), range)?;
1904 Some(format!("type variable '{name}' is unresolved"))
1905 }
1906 _ if ty.instantiation == Instantiation::Unknown => {
1907 Some("type instantiation is unknown".to_owned())
1908 }
1909 _ => None,
1910 };
1911 if reason.is_none() {
1912 reason = unknown;
1913 }
1914 let mut push = |component| -> Result<(), QueryError> {
1915 check_collection(pending.len(), limits.collection, range)?;
1916 pending.push((component, depth + 1));
1917 Ok(())
1918 };
1919 match &ty.kind {
1920 TypeKind::Set(element) => push(element.as_ref())?,
1921 TypeKind::Array { indices, element } => {
1922 push(element.as_ref())?;
1923 for index in indices.iter().rev() {
1924 push(index)?;
1925 }
1926 }
1927 TypeKind::Tuple(fields) => {
1928 for field in fields.iter().rev() {
1929 push(field)?;
1930 }
1931 }
1932 TypeKind::Record(fields) => {
1933 for (name, field) in fields.iter().rev() {
1934 work.spend(name.len(), range)?;
1935 push(field)?;
1936 }
1937 }
1938 _ => {}
1939 }
1940 }
1941 Ok(reason)
1942}
1943
1944fn range_json(range: &Range<usize>) -> Value {
1945 json!({"start": range.start, "end": range.end})
1946}
1947fn binding_json(binding: &BindingResolution) -> Value {
1948 match binding {
1949 BindingResolution::Resolved(id) => json!({"outcome": "resolved", "declaration_id": id.0}),
1950 BindingResolution::Overloads(ids) => {
1951 json!({"outcome": "overloads", "candidates": ids.iter().map(|id| id.0).collect::<Vec<_>>()})
1952 }
1953 BindingResolution::Ambiguous(ids) => {
1954 json!({"outcome": "ambiguous", "candidates": ids.iter().map(|id| id.0).collect::<Vec<_>>()})
1955 }
1956 BindingResolution::Unresolved => json!({"outcome": "unresolved"}),
1957 }
1958}
1959fn call_json(call: &CallOutcome) -> Value {
1960 match call {
1961 CallOutcome::Resolved { declaration, .. } => {
1962 json!({"outcome": "resolved", "declaration_id": declaration.0})
1963 }
1964 CallOutcome::Intrinsic { name, .. } => json!({"outcome": "intrinsic", "name": name}),
1965 CallOutcome::NoMatch { reason } => json!({"outcome": "no_match", "reason": reason}),
1966 CallOutcome::Unresolved { reason } => json!({"outcome": "unresolved", "reason": reason}),
1967 CallOutcome::Ambiguous { candidates } => {
1968 json!({"outcome": "ambiguous", "candidates": candidates.iter().map(|id| id.0).collect::<Vec<_>>()})
1969 }
1970 CallOutcome::Unsupported { reason, candidates } => {
1971 json!({"outcome": "unsupported", "reason": reason, "candidates": candidates.iter().map(|id| id.0).collect::<Vec<_>>()})
1972 }
1973 }
1974}
1975fn type_json(ty: &TypeInst) -> Value {
1976 let mut value = json!({"kind": type_kind(&ty.kind), "instantiation": instantiation_name(ty.instantiation), "optional": ty.optional});
1977 match &ty.kind {
1978 TypeKind::Enum(id) => value["declaration_id"] = json!(id.0),
1979 TypeKind::Set(element) => value["element"] = type_json(element),
1980 TypeKind::Array { indices, element } => {
1981 value["indices"] = json!(indices.iter().map(type_json).collect::<Vec<_>>());
1982 value["element"] = type_json(element);
1983 }
1984 TypeKind::Tuple(fields) => {
1985 value["fields"] = json!(fields.iter().map(type_json).collect::<Vec<_>>())
1986 }
1987 TypeKind::Record(fields) => {
1988 value["fields"] = json!(
1989 fields
1990 .iter()
1991 .map(|(name, ty)| json!({"name": name, "type": type_json(ty)}))
1992 .collect::<Vec<_>>()
1993 )
1994 }
1995 TypeKind::Variable {
1996 name,
1997 enum_only,
1998 any,
1999 } => {
2000 value["name"] = json!(name);
2001 value["enum_only"] = json!(enum_only);
2002 value["any"] = json!(any);
2003 }
2004 TypeKind::Unknown(reason) => value["reason"] = json!(reason),
2005 _ => {}
2006 }
2007 value
2008}
2009
2010pub(crate) fn type_allocation(ty: &TypeInst) -> (usize, usize) {
2012 let mut total = (1, 0);
2013 let mut add = |ty| {
2014 let (units, bytes) = type_allocation(ty);
2015 total.0 += units;
2016 total.1 += bytes;
2017 };
2018 match &ty.kind {
2019 TypeKind::Set(element) => add(element),
2020 TypeKind::Array { indices, element } => {
2021 for index in indices {
2022 add(index);
2023 }
2024 add(element);
2025 }
2026 TypeKind::Tuple(fields) => {
2027 for field in fields {
2028 add(field);
2029 }
2030 }
2031 TypeKind::Record(fields) => {
2032 for (_, field) in fields {
2033 add(field);
2034 }
2035 total.0 += fields.len();
2036 total.1 += fields.iter().map(|(name, _)| name.len()).sum::<usize>();
2037 }
2038 TypeKind::Variable { name, .. } | TypeKind::Unknown(name) => total.1 += name.len(),
2039 _ => {}
2040 }
2041 total
2042}