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
87
use stc_ts_ast_rnode::{RCallExpr, RCallee, RExpr, RMemberExpr, RMemberProp, ROptCall, ROptChainBase, ROptChainExpr};
use stc_ts_errors::DebugExt;
use stc_ts_types::Type;
use stc_utils::ext::TypeVecExt;
use crate::{
analyzer::{
expr::{IdCtx, TypeOfMode},
Analyzer, Ctx,
},
util::RemoveTypes,
validator,
validator::ValidateWith,
VResult,
};
#[validator]
impl Analyzer<'_, '_> {
fn validate(&mut self, node: &ROptChainExpr, type_ann: Option<&Type>) -> VResult<Type> {
let span = node.span;
match &node.base {
ROptChainBase::Member(me) => {
let prop = self.validate_key(
&match &me.prop {
RMemberProp::Ident(i) => RExpr::Ident(i.clone()),
RMemberProp::Computed(c) => *c.expr.clone(),
RMemberProp::PrivateName(p) => RExpr::PrivateName(p.clone()),
},
matches!(me.prop, RMemberProp::Computed(_)),
)?;
let obj = me.obj.validate_with_default(self)?;
let is_obj_optional = self.can_be_undefined(span, &obj, true)?;
let obj = obj.remove_falsy();
let ctx = Ctx {
in_opt_chain: true,
..self.ctx
};
let ty = self
.with_ctx(ctx)
.access_property(span, &obj, &prop, TypeOfMode::RValue, IdCtx::Var, Default::default())
.context("tried to access property to validate an optional chaining expression")?;
if is_obj_optional {
let mut types = vec![Type::undefined(span, Default::default()), ty];
types.dedup_type();
Ok(Type::new_union(span, types))
} else {
Ok(ty)
}
}
ROptChainBase::Call(ce) => ce.validate_with_args(self, type_ann),
}
}
}
#[validator]
impl Analyzer<'_, '_> {
fn validate(&mut self, node: &ROptCall, type_ann: Option<&Type>) -> VResult<Type> {
let span = node.span;
let ty = RCallExpr {
node_id: node.node_id,
span,
callee: RCallee::Expr(node.callee.clone()),
args: node.args.clone(),
type_args: node.type_args.clone(),
}
.validate_with_args(self, type_ann)?;
Ok(Type::new_union(span, vec![Type::undefined(span, Default::default()), ty]))
}
}
pub(crate) fn is_obj_opt_chaining(obj: &RExpr) -> bool {
match obj {
RExpr::OptChain(..) => true,
RExpr::Member(RMemberExpr { obj, .. }) => is_obj_opt_chaining(obj),
_ => false,
}
}