1use crate::{
2 engine_threading::{
3 DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines,
4 OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext,
5 },
6 parsed::QualifiedPathType,
7 Engines, GenericArgument, Ident, Namespace,
8};
9use serde::{Deserialize, Serialize};
10use std::{
11 cmp::Ordering,
12 fmt,
13 hash::{Hash, Hasher},
14 sync::Arc,
15};
16use sway_error::{
17 error::CompileError,
18 handler::{ErrorEmitted, Handler},
19};
20use sway_types::{span::Span, Spanned};
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub struct CallPathTree {
24 pub qualified_call_path: QualifiedCallPath,
25 pub children: Vec<CallPathTree>,
26}
27
28impl HashWithEngines for CallPathTree {
29 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
30 let CallPathTree {
31 qualified_call_path,
32 children,
33 } = self;
34 qualified_call_path.hash(state, engines);
35 children.hash(state, engines);
36 }
37}
38
39impl EqWithEngines for CallPathTree {}
40impl PartialEqWithEngines for CallPathTree {
41 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
42 let CallPathTree {
43 qualified_call_path,
44 children,
45 } = self;
46 qualified_call_path.eq(&other.qualified_call_path, ctx) && children.eq(&other.children, ctx)
47 }
48}
49
50impl<T: PartialEqWithEngines> EqWithEngines for Vec<T> {}
51impl<T: PartialEqWithEngines> PartialEqWithEngines for Vec<T> {
52 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
53 if self.len() != other.len() {
54 return false;
55 }
56 self.iter().zip(other.iter()).all(|(a, b)| a.eq(b, ctx))
57 }
58}
59
60impl OrdWithEngines for CallPathTree {
61 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
62 let CallPathTree {
63 qualified_call_path: l_call_path,
64 children: l_children,
65 } = self;
66 let CallPathTree {
67 qualified_call_path: r_call_path,
68 children: r_children,
69 } = other;
70 l_call_path
71 .cmp(r_call_path, ctx)
72 .then_with(|| l_children.cmp(r_children, ctx))
73 }
74}
75
76#[derive(Clone, Debug, Serialize, Deserialize)]
77
78pub struct QualifiedCallPath {
79 pub call_path: CallPath,
80 pub qualified_path_root: Option<Box<QualifiedPathType>>,
81}
82
83impl std::convert::From<Ident> for QualifiedCallPath {
84 fn from(other: Ident) -> Self {
85 QualifiedCallPath {
86 call_path: CallPath {
87 prefixes: vec![],
88 suffix: other,
89 callpath_type: CallPathType::Ambiguous,
90 },
91 qualified_path_root: None,
92 }
93 }
94}
95
96impl std::convert::From<CallPath> for QualifiedCallPath {
97 fn from(other: CallPath) -> Self {
98 QualifiedCallPath {
99 call_path: other,
100 qualified_path_root: None,
101 }
102 }
103}
104
105impl QualifiedCallPath {
106 pub fn to_call_path(self, handler: &Handler) -> Result<CallPath, ErrorEmitted> {
107 if let Some(qualified_path_root) = self.qualified_path_root {
108 Err(handler.emit_err(CompileError::Internal(
109 "Unexpected qualified path.",
110 qualified_path_root.as_trait_span,
111 )))
112 } else {
113 Ok(self.call_path)
114 }
115 }
116}
117
118impl HashWithEngines for QualifiedCallPath {
119 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
120 let QualifiedCallPath {
121 call_path,
122 qualified_path_root,
123 } = self;
124 call_path.hash(state);
125 qualified_path_root.hash(state, engines);
126 }
127}
128
129impl EqWithEngines for QualifiedCallPath {}
130impl PartialEqWithEngines for QualifiedCallPath {
131 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
132 let QualifiedCallPath {
133 call_path,
134 qualified_path_root,
135 } = self;
136 PartialEqWithEngines::eq(call_path, &other.call_path, ctx)
137 && qualified_path_root.eq(&other.qualified_path_root, ctx)
138 }
139}
140
141impl OrdWithEngines for QualifiedCallPath {
142 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
143 let QualifiedCallPath {
144 call_path: l_call_path,
145 qualified_path_root: l_qualified_path_root,
146 } = self;
147 let QualifiedCallPath {
148 call_path: r_call_path,
149 qualified_path_root: r_qualified_path_root,
150 } = other;
151 l_call_path
152 .cmp(r_call_path)
153 .then_with(|| l_qualified_path_root.cmp(r_qualified_path_root, ctx))
154 }
155}
156
157impl DisplayWithEngines for QualifiedCallPath {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
159 if let Some(qualified_path_root) = &self.qualified_path_root {
160 write!(
161 f,
162 "{}::{}",
163 engines.help_out(qualified_path_root),
164 &self.call_path
165 )
166 } else {
167 write!(f, "{}", &self.call_path)
168 }
169 }
170}
171
172impl DebugWithEngines for QualifiedCallPath {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
174 write!(f, "{}", engines.help_out(self))
175 }
176}
177
178#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
179pub enum CallPathType {
180 RelativeToPackageRoot,
185 Ambiguous,
192 Full,
198}
199
200#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
203pub struct CallPath<T = Ident> {
204 pub prefixes: Vec<Ident>,
205 pub suffix: T,
206 pub callpath_type: CallPathType,
207}
208
209impl EqWithEngines for CallPath {}
210impl PartialEqWithEngines for CallPath {
211 fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool {
212 self.prefixes == other.prefixes
213 && self.suffix == other.suffix
214 && self.callpath_type == other.callpath_type
215 }
216}
217
218impl<T: EqWithEngines> EqWithEngines for CallPath<T> {}
219impl<T: PartialEqWithEngines> PartialEqWithEngines for CallPath<T> {
220 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
221 self.prefixes == other.prefixes
222 && self.suffix.eq(&other.suffix, ctx)
223 && self.callpath_type == other.callpath_type
224 }
225}
226
227impl<T: OrdWithEngines> OrdWithEngines for CallPath<T> {
228 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
229 self.prefixes
230 .cmp(&other.prefixes)
231 .then_with(|| self.suffix.cmp(&other.suffix, ctx))
232 .then_with(|| self.callpath_type.cmp(&other.callpath_type))
233 }
234}
235
236#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
237pub struct ResolvedCallPath<T, U = Ident> {
238 pub decl: T,
239 pub unresolved_call_path: CallPath<U>,
240}
241
242impl std::convert::From<Ident> for CallPath {
243 fn from(other: Ident) -> Self {
244 CallPath {
245 prefixes: vec![],
246 suffix: other,
247 callpath_type: CallPathType::Ambiguous,
248 }
249 }
250}
251
252impl<T> fmt::Display for CallPath<T>
253where
254 T: fmt::Display,
255{
256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257 if let Some((first_prefix, rest_prefixes)) = self.prefixes.split_first() {
261 let first_prefix = if !first_prefix.as_str().contains('-') {
262 first_prefix.as_str()
263 } else {
264 &first_prefix.as_str().replace('-', "_")
265 };
266 write!(f, "{first_prefix}::")?;
267 for prefix in rest_prefixes {
268 write!(f, "{}::", prefix.as_str())?;
269 }
270 }
271 write!(f, "{}", &self.suffix)
272
273 }
278}
279
280impl<T: DisplayWithEngines> DisplayWithEngines for CallPath<T> {
281 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
282 if let Some((first_prefix, rest_prefixes)) = self.prefixes.split_first() {
286 let first_prefix = if !first_prefix.as_str().contains('-') {
287 first_prefix.as_str()
288 } else {
289 &first_prefix.as_str().replace('-', "_")
290 };
291 write!(f, "{first_prefix}::")?;
292 for prefix in rest_prefixes {
293 write!(f, "{}::", prefix.as_str())?;
294 }
295 }
296 write!(f, "{}", engines.help_out(&self.suffix))
297
298 }
303}
304
305impl<T: DisplayWithEngines> DebugWithEngines for CallPath<T> {
306 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
307 for prefix in self.prefixes.iter() {
308 write!(f, "{}::", prefix.as_str())?;
309 }
310 write!(f, "{}", engines.help_out(&self.suffix))
311 }
312}
313
314impl<T: Spanned> Spanned for CallPath<T> {
315 fn span(&self) -> Span {
316 if self.prefixes.is_empty() {
317 self.suffix.span()
318 } else {
319 let suffix_span = self.suffix.span();
320 let mut prefixes_spans = self
321 .prefixes
322 .iter()
323 .map(|x| x.span())
324 .filter(|x| {
331 Arc::ptr_eq(&x.src().text, &suffix_span.src().text)
332 && x.source_id() == suffix_span.source_id()
333 })
334 .peekable();
335 if prefixes_spans.peek().is_some() {
336 Span::join(Span::join_all(prefixes_spans), &suffix_span)
337 } else {
338 suffix_span
339 }
340 }
341 }
342}
343
344pub enum CallPathDisplayType {
346 Regular,
348 StripPackagePrefix,
350}
351
352impl CallPath {
353 pub fn fullpath(path: &[&str]) -> Self {
354 assert!(!path.is_empty());
355
356 CallPath {
357 prefixes: path
358 .iter()
359 .take(path.len() - 1)
360 .map(|&x| Ident::new_no_span(x.into()))
361 .collect(),
362 suffix: path.last().map(|&x| Ident::new_no_span(x.into())).unwrap(),
363 callpath_type: CallPathType::Full,
364 }
365 }
366
367 pub fn rshift(&self) -> CallPath {
370 if self.prefixes.is_empty()
371 || (matches!(self.callpath_type, CallPathType::Full) && self.prefixes.len() == 1)
372 {
373 self.clone()
374 } else {
375 CallPath {
376 prefixes: self.prefixes[0..self.prefixes.len() - 1].to_vec(),
377 suffix: self.prefixes.last().unwrap().clone(),
378 callpath_type: self.callpath_type,
379 }
380 }
381 }
382
383 pub fn lshift(&self) -> CallPath {
385 if self.prefixes.is_empty() {
386 self.clone()
387 } else {
388 let new_callpath_type = match self.callpath_type {
389 CallPathType::RelativeToPackageRoot | CallPathType::Ambiguous => {
390 CallPathType::Ambiguous
391 }
392 CallPathType::Full => CallPathType::RelativeToPackageRoot,
393 };
394 CallPath {
395 prefixes: self.prefixes[1..self.prefixes.len()].to_vec(),
396 suffix: self.suffix.clone(),
397 callpath_type: new_callpath_type,
398 }
399 }
400 }
401
402 pub fn as_vec_string(&self) -> Vec<String> {
403 self.prefixes
404 .iter()
405 .map(|p| p.to_string())
406 .chain(std::iter::once(self.suffix.to_string()))
407 .collect::<Vec<_>>()
408 }
409
410 pub fn as_vec_ident(&self) -> Vec<Ident> {
411 self.as_vec_string()
412 .iter()
413 .map(|s| Ident::new_no_span(s.clone()))
414 .collect::<Vec<_>>()
415 }
416
417 pub fn ident_to_fullpath(suffix: Ident, namespace: &Namespace) -> CallPath {
423 let mut res: Self = suffix.clone().into();
424 for mod_path in namespace.current_mod_path() {
425 res.prefixes.push(mod_path.clone())
426 }
427 res.callpath_type = CallPathType::Full;
428 res
429 }
430
431 pub fn to_import_path(&self, engines: &Engines, namespace: &Namespace) -> CallPath {
438 let converted = self.to_fullpath(engines, namespace);
439
440 if let Some(first) = converted.prefixes.first() {
441 if namespace.current_package_name() == first {
442 return converted.lshift();
443 }
444 }
445 converted
446 }
447
448 pub fn to_display_path(
449 &self,
450 display_type: CallPathDisplayType,
451 namespace: &Namespace,
452 ) -> CallPath {
453 let mut display_path = self.clone();
454
455 match display_type {
456 CallPathDisplayType::Regular => {}
457 CallPathDisplayType::StripPackagePrefix => {
458 if let Some(first) = self.prefixes.first() {
459 if namespace.current_package_name() == first {
460 display_path = display_path.lshift();
461 }
462 }
463 }
464 };
465
466 display_path
467 }
468
469 pub(crate) fn to_string_with_args(
477 &self,
478 engines: &Engines,
479 args: &[GenericArgument],
480 ) -> String {
481 let args = args
482 .iter()
483 .map(|type_arg| engines.help_out(type_arg).to_string())
484 .collect::<Vec<_>>()
485 .join(", ");
486
487 format!(
488 "{}{}",
489 &self,
492 if args.is_empty() {
493 String::new()
494 } else {
495 format!("<{args}>")
496 }
497 )
498 }
499}
500
501impl<T: Clone> CallPath<T> {
502 pub fn to_fullpath(&self, engines: &Engines, namespace: &Namespace) -> CallPath<T> {
518 self.to_fullpath_from_mod_path(engines, namespace, namespace.current_mod_path())
519 }
520
521 pub fn to_fullpath_from_mod_path(
538 &self,
539 engines: &Engines,
540 namespace: &Namespace,
541 mod_path: &Vec<Ident>,
542 ) -> CallPath<T> {
543 let mod_path_module = namespace.module_from_absolute_path(mod_path);
544
545 match self.callpath_type {
546 CallPathType::Full => self.clone(),
547 CallPathType::RelativeToPackageRoot => {
548 let mut prefixes = vec![mod_path[0].clone()];
549 for ident in self.prefixes.iter() {
550 prefixes.push(ident.clone());
551 }
552 Self {
553 prefixes,
554 suffix: self.suffix.clone(),
555 callpath_type: CallPathType::Full,
556 }
557 }
558 CallPathType::Ambiguous => {
559 if self.prefixes.is_empty() {
560 CallPath {
564 prefixes: mod_path.clone(),
565 suffix: self.suffix.clone(),
566 callpath_type: CallPathType::Full,
567 }
568 } else if mod_path_module.is_some()
569 && (mod_path_module.unwrap().has_submodule(&self.prefixes[0])
570 || namespace.module_has_binding(engines, mod_path, &self.prefixes[0]))
571 {
572 CallPath {
579 prefixes: mod_path.iter().chain(&self.prefixes).cloned().collect(),
580 suffix: self.suffix.clone(),
581 callpath_type: CallPathType::Full,
582 }
583 } else if namespace.package_exists(&self.prefixes[0])
584 && namespace.module_is_external(&self.prefixes)
585 {
586 CallPath {
588 prefixes: self.prefixes.clone(),
589 suffix: self.suffix.clone(),
590 callpath_type: CallPathType::Full,
591 }
592 } else {
593 CallPath {
596 prefixes: mod_path.iter().chain(&self.prefixes).cloned().collect(),
597 suffix: self.suffix.clone(),
598 callpath_type: CallPathType::Full,
599 }
600 }
601 }
602 }
603 }
604}
605
606impl CallPath {
607 pub fn to_canonical_path(&self, engines: &Engines, namespace: &Namespace) -> CallPath {
621 let full_path = self.to_fullpath(engines, namespace);
623
624 match namespace.module_from_absolute_path(&full_path.prefixes) {
625 Some(module) => {
626 match module.resolve_symbol(&Handler::default(), engines, &full_path.suffix) {
628 Ok((decl, decl_path)) => {
629 let name = decl.expect_typed().get_name(engines);
630 let suffix = if name.as_str() != full_path.suffix.as_str() {
631 name
632 } else {
633 full_path.suffix
634 };
635 CallPath {
637 prefixes: decl_path,
638 suffix,
639 callpath_type: full_path.callpath_type,
640 }
641 }
642 Err(_) => {
643 full_path
646 }
647 }
648 }
649 None => {
650 full_path
653 }
654 }
655 }
656}