go_types/check/
call.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4//
5//
6// This code is adapted from the offical Go code written in Go
7// with license as follows:
8// Copyright 2013 The Go Authors. All rights reserved.
9// Use of this source code is governed by a BSD-style
10// license that can be found in the LICENSE file.
11
12#![allow(dead_code)]
13use crate::SourceRead;
14
15use super::super::lookup::{self, LookupResult, MethodSet};
16use super::super::obj::EntityType;
17use super::super::objects::TypeKey;
18use super::super::operand::{Operand, OperandMode};
19use super::super::selection::{Selection, SelectionKind};
20use super::super::typ;
21use super::super::universe::ExprKind;
22use super::check::{Checker, FilesContext};
23use super::util::{UnpackResult, UnpackedResultLeftovers};
24use go_parser::ast::{CallExpr, Expr, Node, SelectorExpr};
25use go_parser::Pos;
26use std::rc::Rc;
27
28impl<'a, S: SourceRead> Checker<'a, S> {
29    pub fn call(
30        &mut self,
31        x: &mut Operand,
32        e: &Rc<CallExpr>,
33        fctx: &mut FilesContext<S>,
34    ) -> ExprKind {
35        self.expr_or_type(x, &e.func, fctx);
36
37        let expr = Some(Expr::Call(e.clone()));
38        match x.mode {
39            OperandMode::Invalid => {
40                self.use_exprs(&e.args, fctx);
41                x.expr = expr;
42                ExprKind::Statement
43            }
44            OperandMode::TypeExpr => {
45                // conversion
46                let t = x.typ.unwrap();
47                x.mode = OperandMode::Invalid;
48                match e.args.len() {
49                    0 => self.error(
50                        e.r_paren,
51                        format!("missing argument in conversion to {}", self.new_dis(&t)),
52                    ),
53                    1 => {
54                        self.expr(x, &e.args[0], fctx);
55                        if !x.invalid() {
56                            self.conversion(x, t, fctx);
57                        }
58                    }
59                    _ => {
60                        self.use_exprs(&e.args, fctx);
61                        self.error(
62                            e.args[e.args.len() - 1].pos(self.ast_objs),
63                            format!("too many arguments in conversion to {}", self.new_dis(&t)),
64                        )
65                    }
66                }
67                x.expr = expr;
68                ExprKind::Conversion
69            }
70            OperandMode::Builtin(id) => {
71                if !self.builtin(x, e, id, fctx) {
72                    x.mode = OperandMode::Invalid;
73                }
74                x.expr = expr;
75                // a non-constant result implies a function call
76                self.octx.has_call_or_recv = match x.mode {
77                    OperandMode::Invalid | OperandMode::Constant(_) => false,
78                    _ => true,
79                };
80                self.tc_objs.universe().builtins()[&id].kind
81            }
82            _ => {
83                // function/method call
84                let sig_key = typ::underlying_type(x.typ.unwrap(), self.tc_objs);
85                if let Some(sig) = self.otype(sig_key).try_as_signature() {
86                    let sig_results = sig.results();
87                    let variadic = sig.variadic();
88                    let pcount = sig.params_count(self.tc_objs);
89                    let result = self.unpack(&e.args, pcount, false, variadic, fctx);
90                    match result {
91                        UnpackResult::Error => x.mode = OperandMode::Invalid,
92                        _ => {
93                            let (count, _) = result.rhs_count();
94                            let re = UnpackedResultLeftovers::new(&result, None);
95                            self.arguments(x, e, sig_key, &re, count, fctx);
96                        }
97                    }
98
99                    // determine result
100                    let sigre = self.tc_objs.types[sig_results].try_as_tuple().unwrap();
101                    match sigre.vars().len() {
102                        0 => x.mode = OperandMode::NoValue,
103                        1 => {
104                            x.mode = OperandMode::Value;
105                            x.typ = self.lobj(sigre.vars()[0]).typ(); // unpack tuple
106                        }
107                        _ => {
108                            x.mode = OperandMode::Value;
109                            x.typ = Some(sig_results);
110                        }
111                    }
112                    self.octx.has_call_or_recv = true;
113                } else {
114                    let dis = self.new_dis(x);
115                    self.invalid_op(dis.pos(), &format!("cannot call non-function {}", dis));
116                    x.mode = OperandMode::Invalid;
117                }
118                x.expr = expr;
119                ExprKind::Statement
120            }
121        }
122    }
123
124    /// arguments checks argument passing for the call with the given signature.
125    pub fn arguments(
126        &mut self,
127        x: &mut Operand,
128        call: &CallExpr,
129        sig: TypeKey,
130        re: &UnpackedResultLeftovers,
131        n: usize,
132        fctx: &mut FilesContext<S>,
133    ) {
134        let sig_val = self.otype(sig).try_as_signature().unwrap();
135        let variadic = sig_val.variadic();
136        let params = self.otype(sig_val.params()).try_as_tuple().unwrap();
137        let params_len = params.vars().len();
138        if let Some(ell) = call.ellipsis {
139            if !variadic {
140                let dis = self.new_dis(&call.func);
141                self.error(
142                    ell,
143                    format!("cannot use ... in call to non-variadic {}", dis),
144                );
145                re.use_all(self, fctx);
146                return;
147            }
148            if call.args.len() == 1 && n > 1 {
149                let dis = self.new_dis(&call.args[0]);
150                self.error(ell, format!("cannot use ... with {}-valued {}", n, dis));
151                re.use_all(self, fctx);
152                return;
153            }
154        }
155
156        // evaluate arguments
157        let note = &format!("argument to {}", self.new_dis(&call.func));
158        for i in 0..n {
159            re.get(self, x, i, fctx);
160            if !x.invalid() {
161                let ellipsis = if i == n - 1 { call.ellipsis } else { None };
162                self.argument(sig, i, x, ellipsis, note, fctx);
163            }
164        }
165
166        // check argument count
167        // a variadic function accepts an "empty"
168        // last argument: count one extra
169        let count = if variadic { n + 1 } else { n };
170        if count < params_len {
171            let dis = self.new_dis(&call.func);
172            self.error(
173                call.r_paren,
174                format!("too few arguments in call to {}", dis),
175            );
176        }
177    }
178
179    /// argument checks passing of argument x to the i'th parameter of the given signature.
180    /// If ellipsis is_some(), the argument is followed by ... at that position in the call.
181    fn argument(
182        &mut self,
183        sig: TypeKey,
184        i: usize,
185        x: &mut Operand,
186        ellipsis: Option<Pos>,
187        note: &str,
188        fctx: &mut FilesContext<S>,
189    ) {
190        self.single_value(x);
191        if x.invalid() {
192            return;
193        }
194
195        let sig_val = self.otype(sig).try_as_signature().unwrap();
196        let params = self.otype(sig_val.params()).try_as_tuple().unwrap();
197        let n = params.vars().len();
198
199        let mut ty = if i < n {
200            self.lobj(params.vars()[i]).typ().unwrap()
201        } else if sig_val.variadic() {
202            let t = self.lobj(params.vars()[n - 1]).typ().unwrap();
203            if cfg!(debug_assertions) {
204                if self.otype(t).try_as_slice().is_none() {
205                    let pos = self.lobj(params.vars()[n - 1]).pos();
206                    let td = self.new_dis(&t);
207                    self.dump(
208                        Some(pos),
209                        &format!("expected unnamed slice type, got {}", td),
210                    );
211                }
212            }
213            t
214        } else {
215            self.error_str(x.pos(self.ast_objs), "too many arguments");
216            return;
217        };
218
219        if let Some(pos) = ellipsis {
220            // argument is of the form x... and x is single-valued
221            if i != n - 1 {
222                self.error_str(pos, "can only use ... with matching parameter");
223                return;
224            }
225            let xtype = x.typ.unwrap();
226            if self
227                .otype(xtype)
228                .underlying_val(self.tc_objs)
229                .try_as_slice()
230                .is_none()
231                && xtype != self.basic_type(typ::BasicType::UntypedNil)
232            {
233                let xd = self.new_dis(x);
234                let td = self.new_dis(&ty);
235                self.error(
236                    xd.pos(),
237                    format!("cannot use {} as parameter of type {}", xd, td),
238                );
239                return;
240            }
241        } else if sig_val.variadic() && i >= n - 1 {
242            ty = self.otype(ty).try_as_slice().unwrap().elem();
243        }
244
245        self.assignment(x, Some(ty), note, fctx);
246    }
247
248    pub fn selector(&mut self, x: &mut Operand, e: &Rc<SelectorExpr>, fctx: &mut FilesContext<S>) {
249        let err_exit = |x: &mut Operand| {
250            x.mode = OperandMode::Invalid;
251            x.expr = Some(Expr::Selector(e.clone()));
252        };
253
254        // If the identifier refers to a package, handle everything here
255        // so we don't need a "package" mode for operands: package names
256        // can only appear in qualified identifiers which are mapped to
257        // selector expressions.
258        match &e.expr {
259            Expr::Ident(ikey) => {
260                let ident = self.ast_ident(*ikey);
261                if let Some(okey) = self.lookup(&ident.name) {
262                    let lobj = &mut self.tc_objs.lobjs[okey];
263                    let lobj_pkg = lobj.pkg();
264                    match lobj.entity_type_mut() {
265                        EntityType::PkgName(imported, used) => {
266                            debug_assert_eq!(self.pkg, lobj_pkg.unwrap());
267                            self.result.record_use(*ikey, okey);
268                            *used = true;
269                            let pkg = &self.tc_objs.pkgs[*imported];
270                            let sel_name = &self.ast_objs.idents[e.sel].name;
271                            let exp_op = self.tc_objs.scopes[*pkg.scope()].lookup(sel_name);
272                            if exp_op.is_none() {
273                                if !pkg.fake() {
274                                    let pos = self.ast_ident(e.sel).pos;
275                                    let msg = format!(
276                                        "{} not declared by package {}",
277                                        sel_name,
278                                        pkg.name().as_ref().unwrap()
279                                    );
280                                    self.error(pos, msg);
281                                }
282                                return err_exit(x);
283                            }
284                            let exp = self.lobj(*exp_op.unwrap());
285                            if !exp.exported() {
286                                let pos = self.ast_ident(e.sel).pos;
287                                let msg = format!(
288                                    "{} not declared by package {}",
289                                    sel_name,
290                                    pkg.name().as_ref().unwrap()
291                                );
292                                self.error(pos, msg);
293                            }
294                            self.result.record_use(e.sel, *exp_op.unwrap());
295
296                            // Simplified version of the code for ast::Idents:
297                            // - imported objects are always fully initialized
298                            let exp = self.lobj(*exp_op.unwrap());
299                            x.mode = match exp.entity_type() {
300                                EntityType::Const(v) => OperandMode::Constant(v.clone()),
301                                EntityType::TypeName => OperandMode::TypeExpr,
302                                EntityType::Var(_) => OperandMode::Variable,
303                                EntityType::Func(_) => OperandMode::Value,
304                                EntityType::Builtin(id) => OperandMode::Builtin(*id),
305                                _ => unreachable!(),
306                            };
307                            x.typ = exp.typ();
308                            x.expr = Some(Expr::Selector(e.clone()));
309                            return;
310                        }
311                        _ => {}
312                    }
313                }
314            }
315            _ => {}
316        }
317
318        self.expr_or_type(x, &e.expr, fctx);
319        if x.invalid() {
320            return err_exit(x);
321        }
322
323        let sel_name = &self.ast_objs.idents[e.sel].name;
324        let result = lookup::lookup_field_or_method(
325            x.typ.unwrap(),
326            x.mode == OperandMode::Variable,
327            Some(self.pkg),
328            sel_name,
329            self.tc_objs,
330        );
331
332        let (okey, indices, indirect) = match result {
333            LookupResult::Entry(okey, indices, indirect) => (okey, indices, indirect),
334            _ => {
335                let pos = self.ast_ident(e.sel).pos;
336                let msg = match &result {
337                    LookupResult::Ambiguous(_) => format!("ambiguous selector {}", sel_name),
338                    LookupResult::NotFound => {
339                        let ed = self.new_dis(x.expr.as_ref().unwrap());
340                        let td = self.new_td_o(&x.typ);
341                        format!(
342                            "{}.{} undefined (type {} has no field or method {})",
343                            ed, sel_name, td, sel_name
344                        )
345                    }
346                    LookupResult::BadMethodReceiver => {
347                        let td = self.new_td_o(&x.typ);
348                        format!("{} is not in method set of {}", sel_name, td)
349                    }
350                    LookupResult::Entry(_, _, _) => unreachable!(),
351                };
352                self.error(pos, msg);
353                return err_exit(x);
354            }
355        };
356
357        // methods may not have a fully set up signature yet
358        if self.lobj(okey).entity_type().is_func() {
359            self.obj_decl(okey, None, fctx);
360        }
361
362        let sel_name = &self.ast_objs.idents[e.sel].name;
363        if x.mode == OperandMode::TypeExpr {
364            // method expression
365            match self.lobj(okey).entity_type() {
366                EntityType::Func(_) => {
367                    let selection = Selection::new(
368                        SelectionKind::MethodExpr,
369                        x.typ,
370                        okey,
371                        indices,
372                        indirect,
373                        self.tc_objs,
374                    );
375                    self.result.record_selection(e, selection);
376
377                    // the receiver type becomes the type of the first function
378                    // argument of the method expression's function type
379                    let var = self
380                        .tc_objs
381                        .new_var(0, Some(self.pkg), "".to_owned(), x.typ);
382                    let lobj = self.lobj(okey);
383                    let sig = self.otype(lobj.typ().unwrap()).try_as_signature().unwrap();
384                    let (p, r, v) = (sig.params(), sig.results(), sig.variadic());
385                    let params_val = self.otype(p).try_as_tuple().unwrap();
386                    let mut vars = vec![var];
387                    vars.append(&mut params_val.vars().clone());
388                    let params = self.tc_objs.new_t_tuple(vars);
389                    let new_sig = self.tc_objs.new_t_signature(None, None, params, r, v);
390                    x.mode = OperandMode::Value;
391                    x.typ = Some(new_sig);
392
393                    self.add_decl_dep(okey);
394                }
395                _ => {
396                    let ed = self.new_dis(x.expr.as_ref().unwrap());
397                    let td = self.new_td_o(&x.typ);
398                    let msg = format!(
399                        "{}.{} undefined (type {} has no method {})",
400                        ed, sel_name, td, sel_name
401                    );
402                    self.error(self.ast_ident(e.sel).pos, msg);
403                    return err_exit(x);
404                }
405            }
406        } else {
407            // regular selector
408            let lobj = &self.tc_objs.lobjs[okey];
409            match lobj.entity_type() {
410                EntityType::Var(_) => {
411                    let selection = Selection::new(
412                        SelectionKind::FieldVal,
413                        x.typ,
414                        okey,
415                        indices,
416                        indirect,
417                        self.tc_objs,
418                    );
419                    self.result.record_selection(e, selection);
420                    x.mode = if x.mode == OperandMode::Variable || indirect {
421                        OperandMode::Variable
422                    } else {
423                        OperandMode::Value
424                    };
425                    x.typ = lobj.typ();
426                }
427                EntityType::Func(_) => {
428                    let selection = Selection::new(
429                        SelectionKind::MethodVal,
430                        x.typ,
431                        okey,
432                        indices,
433                        indirect,
434                        self.tc_objs,
435                    );
436                    self.result.record_selection(e, selection);
437
438                    if cfg!(debug_assertions) {
439                        // Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
440                        let mut typ = x.typ.unwrap();
441                        if x.mode == OperandMode::Variable {
442                            // If typ is not an (unnamed) pointer or an interface,
443                            // use *typ instead, because the method set of *typ
444                            // includes the methods of typ.
445                            // Variables are addressable, so we can always take their
446                            // address.
447                            if self.otype(typ).try_as_pointer().is_none()
448                                && !typ::is_interface(typ, self.tc_objs)
449                            {
450                                typ = self.tc_objs.new_t_pointer(typ);
451                            }
452                        }
453                        let mset = MethodSet::new(&typ, self.tc_objs);
454                        let re = mset.lookup(&self.pkg, sel_name, self.tc_objs);
455                        if re.is_none() || re.unwrap().obj() != okey {
456                            let obj_name = self.lobj(okey).name();
457                            let expr = Expr::Selector(e.clone());
458                            let ed = self.new_dis(&expr);
459                            let td = self.new_dis(&typ);
460                            let md = self.new_dis(re.unwrap());
461                            self.dump(
462                                None,
463                                &format!("{}: ({}).{} -> {}", ed.pos(), td, obj_name, md),
464                            );
465                            self.dump(None, &format!("{}\n", self.new_dis(&mset)));
466                            panic!("method sets and lookup don't agree");
467                        }
468                    }
469
470                    x.mode = OperandMode::Value;
471
472                    // remove receiver
473                    let lobj = &self.tc_objs.lobjs[okey];
474                    let sig = self.otype(lobj.typ().unwrap()).try_as_signature().unwrap();
475                    let (p, r, v) = (sig.params(), sig.results(), sig.variadic());
476                    let new_sig = self.tc_objs.new_t_signature(None, None, p, r, v);
477                    x.typ = Some(new_sig);
478
479                    self.add_decl_dep(okey);
480                }
481                _ => unreachable!(),
482            }
483        }
484        x.expr = Some(Expr::Selector(e.clone()));
485    }
486}