1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::sync::atomic::{AtomicU64, Ordering::SeqCst};

use stc_visit::Visit;
use swc_common::{EqIgnoreSpan, TypeEq};

/// Used to distinguish private class properties.
///
/// # Context
///
/// `derivedClassTransitivity.ts`:
///
///
/// ```ts
/// // subclassing is not transitive when you can remove required parameters and add optional parameters
///
/// class C {
///     foo(x: number) { }
/// }
///
/// class D extends C {
///     foo() { } // ok to drop parameters
/// }
///
/// class E extends D {
///     foo(x?: string) { } // ok to add optional parameters
/// }
///
/// var c: C;
/// var d: D;
/// var e: E;
/// c = e;
/// var r = c.foo(1);
/// var r2 = e.foo('');
/// ```
///
/// ---
///
///
/// As derived class may have different signature than parent class, we can't
/// use super class to assign classes.
///
/// Because of it, we should assign properties directly.
///
/// It means we need a way to know if two class properties are exactly identical
/// i.e. declared in same class.
///
///
/// # Note
///
/// ## Alternative
///
/// [WIP] (Seeing if span is enough)
///
/// `lo` and `hi` of a [swc_common::Span] can be also used to check if two
/// private properties are identical, but I(kdy1) decided to use a new type
/// because
///
/// ## Not data
/// This is not `data` part of class and as a result `type_eq` and
/// `eq_ignore_span` always return `true`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Visit)]
pub struct ClassId(u64);

impl ClassId {
    pub fn generate() -> Self {
        static GENERATOR: AtomicU64 = AtomicU64::new(0);

        let id = GENERATOR.fetch_add(1, SeqCst);

        ClassId(id)
    }
}

/// Always true.
impl TypeEq for ClassId {
    fn type_eq(&self, _: &Self) -> bool {
        true
    }
}

/// Always true.
impl EqIgnoreSpan for ClassId {
    fn eq_ignore_span(&self, _: &Self) -> bool {
        true
    }
}