1use std::{
18 collections::{HashMap, HashSet},
19 fmt::Display,
20 iter::{Chain, Once},
21 sync::Arc,
22 vec,
23};
24
25use cedar_policy_core::{
26 ast::AnyId,
27 impl_diagnostic_from_source_loc_field, impl_diagnostic_from_two_source_loc_fields,
28 impl_diagnostic_from_two_source_loc_opt_fields,
29 parser::{
30 err::{expected_to_string, ExpectedTokenConfig},
31 unescape::UnescapeError,
32 Loc, Node,
33 },
34};
35use lalrpop_util as lalr;
36use lazy_static::lazy_static;
37use miette::{Diagnostic, LabeledSpan, SourceSpan};
38use nonempty::NonEmpty;
39use smol_str::{SmolStr, ToSmolStr};
40use thiserror::Error;
41
42use super::ast::PR;
43
44#[derive(Debug, Clone, PartialEq, Eq, Error)]
45pub enum UserError {
46 #[error("An empty list was passed")]
47 EmptyList(Node<()>),
48 #[error("Invalid escape codes")]
49 StringEscape(Node<NonEmpty<UnescapeError>>),
50 #[error("`{0}` is a reserved identifier")]
51 ReservedIdentifierUsed(Node<SmolStr>),
52 #[error("duplicate annotations: `{}`", .0)]
53 DuplicateAnnotations(AnyId, Node<()>, Node<()>),
54}
55
56impl UserError {
57 pub(crate) fn primary_source_span(&self) -> SourceSpan {
59 match self {
60 Self::EmptyList(n) => n.loc.span,
61 Self::StringEscape(n) => n.loc.span,
62 Self::ReservedIdentifierUsed(n) => n.loc.span,
63 Self::DuplicateAnnotations(_, n, _) => n.loc.span,
65 }
66 }
67}
68
69pub(crate) type RawLocation = usize;
70pub(crate) type RawToken<'a> = lalr::lexer::Token<'a>;
71
72pub(crate) type RawParseError<'a> = lalr::ParseError<RawLocation, RawToken<'a>, UserError>;
73pub(crate) type RawErrorRecovery<'a> = lalr::ErrorRecovery<RawLocation, RawToken<'a>, UserError>;
74
75type OwnedRawParseError = lalr::ParseError<RawLocation, String, UserError>;
76
77lazy_static! {
78 static ref SCHEMA_TOKEN_CONFIG: ExpectedTokenConfig = ExpectedTokenConfig {
79 friendly_token_names: HashMap::from([
80 ("IN", "`in`"),
81 ("PRINCIPAL", "`principal`"),
82 ("ACTION", "`action`"),
83 ("RESOURCE", "`resource`"),
84 ("CONTEXT", "`context`"),
85 ("STRINGLIT", "string literal"),
86 ("ENTITY", "`entity`"),
87 ("NAMESPACE", "`namespace`"),
88 ("TYPE", "`type`"),
89 ("SET", "`Set`"),
90 ("IDENTIFIER", "identifier"),
91 ("TAGS", "`tags`"),
92 ("ENUM", "`enum`"),
93 ]),
94 impossible_tokens: HashSet::new(),
95 special_identifier_tokens: HashSet::from([
96 "NAMESPACE",
97 "ENTITY",
98 "IN",
99 "TYPE",
100 "APPLIESTO",
101 "PRINCIPAL",
102 "ACTION",
103 "RESOURCE",
104 "CONTEXT",
105 "ATTRIBUTES",
106 "TAGS",
107 "LONG",
108 "STRING",
109 "BOOL",
110 "ENUM",
111 ]),
112 identifier_sentinel: "IDENTIFIER",
113 first_set_identifier_tokens: HashSet::from(["SET"]),
114 first_set_sentinel: "\"{\"",
115 };
116}
117
118#[derive(Clone, Debug, PartialEq, Eq)]
120pub struct ParseError {
121 pub(crate) err: OwnedRawParseError,
123 src: Arc<str>,
125}
126
127impl ParseError {
128 pub(crate) fn from_raw_parse_error(err: RawParseError<'_>, src: Arc<str>) -> Self {
129 Self {
130 err: err.map_token(|token| token.to_string()),
131 src,
132 }
133 }
134
135 pub(crate) fn from_raw_error_recovery(recovery: RawErrorRecovery<'_>, src: Arc<str>) -> Self {
136 Self::from_raw_parse_error(recovery.error, src)
137 }
138}
139
140impl ParseError {
141 pub fn primary_source_span(&self) -> SourceSpan {
143 match &self.err {
144 OwnedRawParseError::InvalidToken { location } => SourceSpan::from(*location),
145 OwnedRawParseError::UnrecognizedEof { location, .. } => SourceSpan::from(*location),
146 OwnedRawParseError::UnrecognizedToken {
147 token: (token_start, _, token_end),
148 ..
149 } => SourceSpan::from(*token_start..*token_end),
150 OwnedRawParseError::ExtraToken {
151 token: (token_start, _, token_end),
152 } => SourceSpan::from(*token_start..*token_end),
153 OwnedRawParseError::User { error } => error.primary_source_span(),
154 }
155 }
156}
157
158impl Display for ParseError {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 let Self { err, .. } = self;
161 match err {
162 OwnedRawParseError::InvalidToken { .. } => write!(f, "invalid token"),
163 OwnedRawParseError::UnrecognizedEof { .. } => write!(f, "unexpected end of input"),
164 OwnedRawParseError::UnrecognizedToken {
165 token: (_, token, _),
166 ..
167 } => write!(f, "unexpected token `{token}`"),
168 OwnedRawParseError::ExtraToken {
169 token: (_, token, _),
170 ..
171 } => write!(f, "extra token `{token}`"),
172 OwnedRawParseError::User { error } => write!(f, "{error}"),
173 }
174 }
175}
176
177impl std::error::Error for ParseError {}
178
179impl Diagnostic for ParseError {
180 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
181 Some(&self.src as &dyn miette::SourceCode)
182 }
183
184 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
185 let primary_source_span = self.primary_source_span();
186 match &self.err {
187 OwnedRawParseError::InvalidToken { .. } => Some(Box::new(std::iter::once(
188 LabeledSpan::underline(primary_source_span),
189 ))),
190 OwnedRawParseError::UnrecognizedEof { expected, .. } => {
191 Some(Box::new(std::iter::once(LabeledSpan::new_with_span(
192 expected_to_string(expected, &SCHEMA_TOKEN_CONFIG),
193 primary_source_span,
194 ))))
195 }
196 OwnedRawParseError::UnrecognizedToken { expected, .. } => {
197 Some(Box::new(std::iter::once(LabeledSpan::new_with_span(
198 expected_to_string(expected, &SCHEMA_TOKEN_CONFIG),
199 primary_source_span,
200 ))))
201 }
202 OwnedRawParseError::ExtraToken { .. } => Some(Box::new(std::iter::once(
203 LabeledSpan::underline(primary_source_span),
204 ))),
205 OwnedRawParseError::User {
206 error: UserError::DuplicateAnnotations(_, n1, n2),
207 } => Some(Box::new(
208 std::iter::once(n1.loc.span)
209 .chain(std::iter::once(n2.loc.span))
210 .map(LabeledSpan::underline),
211 )),
212 OwnedRawParseError::User { .. } => Some(Box::new(std::iter::once(
213 LabeledSpan::underline(primary_source_span),
214 ))),
215 }
216 }
217}
218
219#[derive(Clone, Debug, PartialEq, Eq)]
221pub struct ParseErrors(pub(crate) Box<NonEmpty<ParseError>>);
222
223impl ParseErrors {
224 pub fn new(first: ParseError, tail: impl IntoIterator<Item = ParseError>) -> Self {
225 Self(Box::new(NonEmpty {
226 head: first,
227 tail: tail.into_iter().collect(),
228 }))
229 }
230
231 pub fn from_iter(i: impl IntoIterator<Item = ParseError>) -> Option<Self> {
232 let v = i.into_iter().collect::<Vec<_>>();
233 Some(Self(Box::new(NonEmpty::from_vec(v)?)))
234 }
235
236 pub fn iter(&self) -> impl Iterator<Item = &ParseError> {
238 self.0.iter()
239 }
240}
241
242impl Display for ParseErrors {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 write!(f, "{}", self.0.first())
245 }
246}
247
248impl IntoIterator for ParseErrors {
249 type Item = ParseError;
250 type IntoIter = Chain<Once<ParseError>, vec::IntoIter<ParseError>>;
251
252 fn into_iter(self) -> Self::IntoIter {
253 self.0.into_iter()
254 }
255}
256
257impl std::error::Error for ParseErrors {
258 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
259 std::error::Error::source(self.0.first())
260 }
261}
262
263impl Diagnostic for ParseErrors {
268 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
269 let mut errs = self.iter().map(|err| err as &dyn Diagnostic);
271 errs.next().map(move |first_err| match first_err.related() {
272 Some(first_err_related) => Box::new(first_err_related.chain(errs)),
273 None => Box::new(errs) as Box<dyn Iterator<Item = _>>,
274 })
275 }
276
277 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
278 Diagnostic::code(self.0.first())
279 }
280
281 fn severity(&self) -> Option<miette::Severity> {
282 Diagnostic::severity(self.0.first())
283 }
284
285 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
286 Diagnostic::help(self.0.first())
287 }
288
289 fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
290 Diagnostic::url(self.0.first())
291 }
292
293 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
294 Diagnostic::source_code(self.0.first())
295 }
296
297 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
298 Diagnostic::labels(self.0.first())
299 }
300
301 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
302 Diagnostic::diagnostic_source(self.0.first())
303 }
304}
305
306#[derive(Debug, Clone, PartialEq, Eq)]
309pub struct ToJsonSchemaErrors(NonEmpty<ToJsonSchemaError>);
310
311impl ToJsonSchemaErrors {
312 pub fn new(errs: NonEmpty<ToJsonSchemaError>) -> Self {
314 Self(errs)
315 }
316
317 pub fn iter(&self) -> impl Iterator<Item = &ToJsonSchemaError> {
319 self.0.iter()
320 }
321}
322
323impl IntoIterator for ToJsonSchemaErrors {
324 type Item = ToJsonSchemaError;
325 type IntoIter = <NonEmpty<ToJsonSchemaError> as IntoIterator>::IntoIter;
326
327 fn into_iter(self) -> Self::IntoIter {
328 self.0.into_iter()
329 }
330}
331
332impl From<ToJsonSchemaError> for ToJsonSchemaErrors {
333 fn from(value: ToJsonSchemaError) -> Self {
334 Self(NonEmpty::singleton(value))
335 }
336}
337
338impl Display for ToJsonSchemaErrors {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 write!(f, "{}", self.0.first()) }
342}
343
344impl std::error::Error for ToJsonSchemaErrors {
345 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
346 self.0.first().source()
347 }
348
349 #[allow(deprecated)]
350 fn description(&self) -> &str {
351 self.0.first().description()
352 }
353
354 #[allow(deprecated)]
355 fn cause(&self) -> Option<&dyn std::error::Error> {
356 self.0.first().cause()
357 }
358}
359
360impl Diagnostic for ToJsonSchemaErrors {
365 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
366 let mut errs = self.iter().map(|err| err as &dyn Diagnostic);
368 errs.next().map(move |first_err| match first_err.related() {
369 Some(first_err_related) => Box::new(first_err_related.chain(errs)),
370 None => Box::new(errs) as Box<dyn Iterator<Item = _>>,
371 })
372 }
373
374 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
375 self.0.first().code()
376 }
377
378 fn severity(&self) -> Option<miette::Severity> {
379 self.0.first().severity()
380 }
381
382 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
383 self.0.first().help()
384 }
385
386 fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
387 self.0.first().url()
388 }
389
390 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
391 self.0.first().source_code()
392 }
393
394 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
395 self.0.first().labels()
396 }
397
398 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
399 self.0.first().diagnostic_source()
400 }
401}
402
403#[derive(Clone, Debug, Error, PartialEq, Eq, Diagnostic)]
406pub enum ToJsonSchemaError {
407 #[error(transparent)]
409 #[diagnostic(transparent)]
410 DuplicateDeclarations(#[from] DuplicateDeclarations),
411 #[error(transparent)]
413 #[diagnostic(transparent)]
414 DuplicateContext(#[from] DuplicateContext),
415 #[error(transparent)]
417 #[diagnostic(transparent)]
418 DuplicatePrincipalOrResource(#[from] DuplicatePrincipalOrResource),
419 #[error(transparent)]
421 #[diagnostic(transparent)]
422 NoPrincipalOrResource(#[from] NoPrincipalOrResource),
423 #[error(transparent)]
425 #[diagnostic(transparent)]
426 DuplicateNamespaces(#[from] DuplicateNamespace),
427 #[error(transparent)]
429 #[diagnostic(transparent)]
430 UnknownTypeName(#[from] UnknownTypeName),
431 #[error(transparent)]
433 #[diagnostic(transparent)]
434 ReservedName(#[from] ReservedName),
435 #[error(transparent)]
437 #[diagnostic(transparent)]
438 ReservedSchemaKeyword(#[from] ReservedSchemaKeyword),
439}
440
441impl ToJsonSchemaError {
442 pub(crate) fn duplicate_context(name: &impl ToSmolStr, loc1: Loc, loc2: Loc) -> Self {
443 Self::DuplicateContext(DuplicateContext {
444 name: name.to_smolstr(),
445 loc1,
446 loc2,
447 })
448 }
449
450 pub(crate) fn duplicate_decls(decl: &impl ToSmolStr, loc1: Loc, loc2: Loc) -> Self {
451 Self::DuplicateDeclarations(DuplicateDeclarations {
452 decl: decl.to_smolstr(),
453 loc1,
454 loc2,
455 })
456 }
457
458 pub(crate) fn duplicate_namespace(
459 namespace_id: &impl ToSmolStr,
460 loc1: Option<Loc>,
461 loc2: Option<Loc>,
462 ) -> Self {
463 Self::DuplicateNamespaces(DuplicateNamespace {
464 namespace_id: namespace_id.to_smolstr(),
465 loc1,
466 loc2,
467 })
468 }
469
470 pub(crate) fn duplicate_principal(name: &impl ToSmolStr, loc1: Loc, loc2: Loc) -> Self {
471 Self::DuplicatePrincipalOrResource(DuplicatePrincipalOrResource {
472 name: name.to_smolstr(),
473 kind: PR::Principal,
474 loc1,
475 loc2,
476 })
477 }
478
479 pub(crate) fn duplicate_resource(name: &impl ToSmolStr, loc1: Loc, loc2: Loc) -> Self {
480 Self::DuplicatePrincipalOrResource(DuplicatePrincipalOrResource {
481 name: name.to_smolstr(),
482 kind: PR::Resource,
483 loc1,
484 loc2,
485 })
486 }
487
488 pub(crate) fn no_principal(name: &impl ToSmolStr, name_loc: Loc) -> Self {
489 Self::NoPrincipalOrResource(NoPrincipalOrResource {
490 kind: PR::Principal,
491 name: name.to_smolstr(),
492 missing_or_empty: MissingOrEmpty::Missing,
493 name_loc,
494 })
495 }
496
497 pub(crate) fn no_resource(name: &impl ToSmolStr, name_loc: Loc) -> Self {
498 Self::NoPrincipalOrResource(NoPrincipalOrResource {
499 kind: PR::Resource,
500 name: name.to_smolstr(),
501 missing_or_empty: MissingOrEmpty::Missing,
502 name_loc,
503 })
504 }
505
506 pub(crate) fn empty_principal(name: &impl ToSmolStr, name_loc: Loc, loc: Loc) -> Self {
507 Self::NoPrincipalOrResource(NoPrincipalOrResource {
508 kind: PR::Principal,
509 name: name.to_smolstr(),
510 missing_or_empty: MissingOrEmpty::Empty { loc },
511 name_loc,
512 })
513 }
514
515 pub(crate) fn empty_resource(name: &impl ToSmolStr, name_loc: Loc, loc: Loc) -> Self {
516 Self::NoPrincipalOrResource(NoPrincipalOrResource {
517 kind: PR::Resource,
518 name: name.to_smolstr(),
519 missing_or_empty: MissingOrEmpty::Empty { loc },
520 name_loc,
521 })
522 }
523
524 pub(crate) fn reserved_name(name: &impl ToSmolStr, loc: Loc) -> Self {
525 Self::ReservedName(ReservedName {
526 name: name.to_smolstr(),
527 loc,
528 })
529 }
530
531 pub(crate) fn reserved_keyword(keyword: &impl ToSmolStr, loc: Loc) -> Self {
532 Self::ReservedSchemaKeyword(ReservedSchemaKeyword {
533 keyword: keyword.to_smolstr(),
534 loc,
535 })
536 }
537}
538
539#[derive(Debug, Clone, PartialEq, Eq, Error)]
540#[error("this uses a reserved schema keyword: `{keyword}`")]
541pub struct ReservedSchemaKeyword {
542 keyword: SmolStr,
543 loc: Loc,
544}
545
546impl Diagnostic for ReservedSchemaKeyword {
547 impl_diagnostic_from_source_loc_field!(loc);
548
549 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
550 Some(Box::new("Keywords such as `entity`, `extension`, `set` and `record` cannot be used as common type names"))
551 }
552}
553
554#[derive(Debug, Clone, PartialEq, Eq, Error)]
555#[error("use of the reserved `__cedar` namespace")]
556pub struct ReservedName {
557 name: SmolStr,
558 loc: Loc,
559}
560
561impl Diagnostic for ReservedName {
562 impl_diagnostic_from_source_loc_field!(loc);
563
564 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
565 Some(Box::new(
566 "Names containing `__cedar` (for example: `__cedar::A`, `A::__cedar`, or `A::__cedar::B`) are reserved",
567 ))
568 }
569}
570
571#[derive(Debug, Clone, PartialEq, Eq, Error)]
572#[error("unknown type name: `{name}`")]
573pub struct UnknownTypeName {
574 name: SmolStr,
575 loc: Loc,
576}
577
578impl Diagnostic for UnknownTypeName {
579 impl_diagnostic_from_source_loc_field!(loc);
580
581 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
582 let msg = format!(
583 "Did you mean to define `{}` as an entity type or common type?",
584 self.name
585 );
586 Some(Box::new(msg))
587 }
588}
589
590#[derive(Debug, Clone, PartialEq, Eq, Error)]
591#[error("duplicate `{kind}` declaration in action `{name}`")]
592pub struct DuplicatePrincipalOrResource {
593 name: SmolStr,
594 kind: PR,
595 loc1: Loc,
596 loc2: Loc,
597}
598
599impl Diagnostic for DuplicatePrincipalOrResource {
600 impl_diagnostic_from_two_source_loc_fields!(loc1, loc2);
601
602 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
603 let msg = format!("Actions may only have a single {kind} declaration, but a {kind} declaration may specify a list of entity types like `{kind}: [X, Y, Z]`", kind=self.kind);
604 Some(Box::new(msg))
605 }
606}
607
608#[derive(Debug, Clone, PartialEq, Eq, Error)]
609#[error("duplicate context declaration in action `{name}`")]
610pub struct DuplicateContext {
611 name: SmolStr,
612 loc1: Loc,
613 loc2: Loc,
614}
615
616impl Diagnostic for DuplicateContext {
617 impl_diagnostic_from_two_source_loc_fields!(loc1, loc2);
618
619 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
620 Some(Box::new(
621 "Try either deleting one of the declarations, or merging into a single declaration",
622 ))
623 }
624}
625#[derive(Debug, Clone, PartialEq, Eq, Error)]
626#[error("`{decl}` is declared twice")]
627pub struct DuplicateDeclarations {
628 decl: SmolStr,
629 loc1: Loc,
630 loc2: Loc,
631}
632
633impl Diagnostic for DuplicateDeclarations {
634 impl_diagnostic_from_two_source_loc_fields!(loc1, loc2);
635}
636
637#[derive(Debug, Clone, PartialEq, Eq, Error)]
638#[error("{}", match .missing_or_empty {
639 MissingOrEmpty::Missing => format!("missing `{kind}` declaration for `{name}`"),
640 MissingOrEmpty::Empty { .. } => format!("for action `{name}`, `{kind}` is `[]`, which is invalid")
641})]
642pub struct NoPrincipalOrResource {
643 kind: PR,
644 name: SmolStr,
645 missing_or_empty: MissingOrEmpty,
646 name_loc: Loc,
648}
649
650#[derive(Debug, Clone, PartialEq, Eq)]
651enum MissingOrEmpty {
652 Missing,
654 Empty {
656 loc: Loc,
658 },
659}
660
661pub const NO_PR_HELP_MSG: &str =
662 "Every action must define both `principal` and `resource` targets, and the `principal` and `resource` lists must not be `[]`.";
663
664impl Diagnostic for NoPrincipalOrResource {
665 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
666 Some(&self.name_loc.src as &dyn miette::SourceCode)
667 }
668
669 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
670 match &self.missing_or_empty {
671 MissingOrEmpty::Missing => {
672 Some(Box::new(std::iter::once(miette::LabeledSpan::underline(
674 self.name_loc.span,
675 ))))
676 }
677 MissingOrEmpty::Empty { loc } => {
678 let action_name = miette::LabeledSpan::new_with_span(
680 Some("for this action".into()),
681 self.name_loc.span,
682 );
683 let decl =
684 miette::LabeledSpan::new_with_span(Some("must not be `[]`".into()), loc.span);
685 Some(Box::new([action_name, decl].into_iter()))
686 }
687 }
688 }
689
690 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
691 Some(Box::new(NO_PR_HELP_MSG))
692 }
693}
694
695#[derive(Debug, Clone, Error, PartialEq, Eq)]
696#[error("duplicate namespace id: `{namespace_id}`")]
697pub struct DuplicateNamespace {
698 namespace_id: SmolStr,
699 loc1: Option<Loc>,
701 loc2: Option<Loc>,
702}
703
704impl Diagnostic for DuplicateNamespace {
705 impl_diagnostic_from_two_source_loc_opt_fields!(loc1, loc2);
706}
707
708pub mod schema_warnings {
710 use cedar_policy_core::{impl_diagnostic_from_source_loc_field, parser::Loc};
711 use miette::Diagnostic;
712 use smol_str::SmolStr;
713 use thiserror::Error;
714
715 #[derive(Eq, PartialEq, Debug, Clone, Error)]
721 #[error("The name `{name}` shadows a builtin Cedar name. You'll have to refer to the builtin as `__cedar::{name}`.")]
722 pub struct ShadowsBuiltinWarning {
723 pub(crate) name: SmolStr,
724 pub(crate) loc: Loc,
725 }
726
727 impl Diagnostic for ShadowsBuiltinWarning {
728 impl_diagnostic_from_source_loc_field!(loc);
729
730 fn severity(&self) -> Option<miette::Severity> {
731 Some(miette::Severity::Warning)
732 }
733 }
734
735 #[derive(Eq, PartialEq, Debug, Clone, Error)]
741 #[error("The common type name {name} shadows an entity name")]
742 pub struct ShadowsEntityWarning {
743 pub(crate) name: SmolStr,
744 pub(crate) entity_loc: Loc,
745 pub(crate) common_loc: Loc,
746 }
747
748 impl Diagnostic for ShadowsEntityWarning {
749 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
750 Some(Box::new(
751 std::iter::once(&self.entity_loc)
752 .chain(std::iter::once(&self.common_loc))
753 .map(miette::LabeledSpan::underline),
754 ))
755 }
756
757 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
758 Some(&self.entity_loc.src as _)
762 }
763
764 fn severity(&self) -> Option<miette::Severity> {
765 Some(miette::Severity::Warning)
766 }
767 }
768}
769
770#[derive(Eq, PartialEq, Debug, Clone, Error, Diagnostic)]
776#[non_exhaustive]
777pub enum SchemaWarning {
778 #[error(transparent)]
780 #[diagnostic(transparent)]
781 ShadowsBuiltin(#[from] schema_warnings::ShadowsBuiltinWarning),
782 #[error(transparent)]
784 #[diagnostic(transparent)]
785 ShadowsEntity(#[from] schema_warnings::ShadowsEntityWarning),
786}