1 use crate::ast_types::Path as RacerPath;
2 use crate::ast_types::{
3 self, GenericsArgs, ImplHeader, Pat, PathAlias, PathAliasKind, TraitBounds, Ty,
4 };
5 use crate::core::{self, BytePos, ByteRange, Match, MatchType, Scope, Session, SessionExt};
6 use crate::nameres;
7 use crate::typeinf;
8
9 use std::path::Path;
10 use std::rc::Rc;
11
12 use rustc_ast::ast::{self, ExprKind, FnRetTy, ItemKind, PatKind, UseTree, UseTreeKind};
13 use rustc_ast::{self, visit};
14 use rustc_data_structures::sync::Lrc;
15 use rustc_errors::emitter::Emitter;
16 use rustc_errors::{Diagnostic, Handler};
17 use rustc_parse::new_parser_from_source_str;
18 use rustc_parse::parser::{ForceCollect, Parser};
19 use rustc_session::parse::ParseSess;
20 use rustc_span::edition::Edition;
21 use rustc_span::source_map::{self, FileName, SourceMap};
22 use rustc_span::Span;
23
24 struct DummyEmitter;
25
26 impl Emitter for DummyEmitter {
emit_diagnostic(&mut self, _db: &Diagnostic)27 fn emit_diagnostic(&mut self, _db: &Diagnostic) {}
source_map(&self) -> Option<&Lrc<SourceMap>>28 fn source_map(&self) -> Option<&Lrc<SourceMap>> {
29 None
30 }
should_show_explain(&self) -> bool31 fn should_show_explain(&self) -> bool {
32 false
33 }
34 }
35
36 /// construct parser from string
37 // From syntax/util/parser_testing.rs
string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_>38 pub fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
39 new_parser_from_source_str(ps, FileName::Custom("racer-file".to_owned()), source_str)
40 }
41
42 /// Get parser from string s and then apply closure f to it
43 // TODO: use Result insated of Option
with_error_checking_parse<F, T>(s: String, f: F) -> Option<T> where F: FnOnce(&mut Parser<'_>) -> Option<T>,44 pub fn with_error_checking_parse<F, T>(s: String, f: F) -> Option<T>
45 where
46 F: FnOnce(&mut Parser<'_>) -> Option<T>,
47 {
48 // FIXME: Set correct edition based on the edition of the target crate.
49 rustc_span::with_session_globals(Edition::Edition2018, || {
50 let codemap = Rc::new(SourceMap::new(source_map::FilePathMapping::empty()));
51 // We use DummyEmitter here not to print error messages to stderr
52 let handler = Handler::with_emitter(false, None, Box::new(DummyEmitter {}));
53 let parse_sess = ParseSess::with_span_handler(handler, codemap);
54
55 let mut p = string_to_parser(&parse_sess, s);
56 f(&mut p)
57 })
58 }
59
60 /// parse string source_str as statement and then apply f to it
61 /// return false if we can't parse s as statement
62 // TODO: make F FnOnce(&ast::Stmt) -> Result<Something, Error>
with_stmt<F>(source_str: String, f: F) -> bool where F: FnOnce(&ast::Stmt),63 pub fn with_stmt<F>(source_str: String, f: F) -> bool
64 where
65 F: FnOnce(&ast::Stmt),
66 {
67 with_error_checking_parse(source_str, |p| {
68 let stmt = match p.parse_stmt(ForceCollect::No) {
69 Ok(Some(stmt)) => stmt,
70 _ => return None,
71 };
72 f(&stmt);
73 Some(())
74 })
75 .is_some()
76 }
77
destruct_span(span: Span) -> (u32, u32)78 pub(crate) fn destruct_span(span: Span) -> (u32, u32) {
79 let source_map::BytePos(lo) = span.lo();
80 let source_map::BytePos(hi) = span.hi();
81 (lo, hi)
82 }
83
get_span_start(span: Span) -> u3284 pub(crate) fn get_span_start(span: Span) -> u32 {
85 let source_map::BytePos(lo) = span.lo();
86 lo
87 }
88
89 /// collect paths from syntax::ast::UseTree
90 #[derive(Debug)]
91 pub struct UseVisitor {
92 pub path_list: Vec<PathAlias>,
93 pub contains_glob: bool,
94 }
95
96 impl<'ast> visit::Visitor<'ast> for UseVisitor {
visit_item(&mut self, i: &ast::Item)97 fn visit_item(&mut self, i: &ast::Item) {
98 // collect items from use tree recursively
99 // returns (Paths, contains_glab)
100 fn collect_nested_items(
101 use_tree: &UseTree,
102 parent_path: Option<&ast_types::Path>,
103 ) -> (Vec<PathAlias>, bool) {
104 let mut res = vec![];
105 let mut path = if let Some(parent) = parent_path {
106 let relative_path = RacerPath::from_ast_nogen(&use_tree.prefix);
107 let mut path = parent.clone();
108 path.extend(relative_path);
109 path
110 } else {
111 RacerPath::from_ast_nogen(&use_tree.prefix)
112 };
113 let mut contains_glob = false;
114 match use_tree.kind {
115 UseTreeKind::Simple(rename, _, _) => {
116 let ident = use_tree.ident().name.to_string();
117 let rename_pos: Option<BytePos> =
118 rename.map(|id| destruct_span(id.span).0.into());
119 let kind = if let Some(last_seg) = path.segments.last() {
120 //` self` is treated normaly in libsyntax,
121 // but we distinguish it here to make completion easy
122 if last_seg.name == "self" {
123 PathAliasKind::Self_(ident, rename_pos)
124 } else {
125 PathAliasKind::Ident(ident, rename_pos)
126 }
127 } else {
128 PathAliasKind::Ident(ident, rename_pos)
129 };
130 if let PathAliasKind::Self_(..) = kind {
131 path.segments.pop();
132 }
133 res.push(PathAlias {
134 kind,
135 path,
136 range: ByteRange::from(use_tree.span),
137 });
138 }
139 UseTreeKind::Nested(ref nested) => {
140 nested.iter().for_each(|(ref tree, _)| {
141 let (items, has_glob) = collect_nested_items(tree, Some(&path));
142 res.extend(items);
143 contains_glob |= has_glob;
144 });
145 }
146 UseTreeKind::Glob => {
147 res.push(PathAlias {
148 kind: PathAliasKind::Glob,
149 path,
150 range: ByteRange::from(use_tree.span),
151 });
152 contains_glob = true;
153 }
154 }
155 (res, contains_glob)
156 }
157 if let ItemKind::Use(ref use_tree) = i.kind {
158 let (path_list, contains_glob) = collect_nested_items(use_tree, None);
159 self.path_list = path_list;
160 self.contains_glob = contains_glob;
161 }
162 }
163 }
164
165 pub struct PatBindVisitor {
166 ident_points: Vec<ByteRange>,
167 }
168
169 impl<'ast> visit::Visitor<'ast> for PatBindVisitor {
visit_local(&mut self, local: &ast::Local)170 fn visit_local(&mut self, local: &ast::Local) {
171 // don't visit the RHS (init) side of the let stmt
172 self.visit_pat(&local.pat);
173 }
174
visit_expr(&mut self, ex: &ast::Expr)175 fn visit_expr(&mut self, ex: &ast::Expr) {
176 // don't visit the RHS or block of an 'if let' or 'for' stmt
177 match &ex.kind {
178 ExprKind::If(let_stmt, ..) | ExprKind::While(let_stmt, ..) => {
179 if let ExprKind::Let(pat, ..) = &let_stmt.kind {
180 self.visit_pat(pat);
181 }
182 }
183 ExprKind::ForLoop(pat, ..) => self.visit_pat(pat),
184 _ => visit::walk_expr(self, ex),
185 }
186 }
187
visit_pat(&mut self, p: &ast::Pat)188 fn visit_pat(&mut self, p: &ast::Pat) {
189 match p.kind {
190 PatKind::Ident(_, ref spannedident, _) => {
191 self.ident_points.push(spannedident.span.into());
192 }
193 _ => {
194 visit::walk_pat(self, p);
195 }
196 }
197 }
198 }
199
200 pub struct PatVisitor {
201 ident_points: Vec<ByteRange>,
202 }
203
204 impl<'ast> visit::Visitor<'ast> for PatVisitor {
visit_pat(&mut self, p: &ast::Pat)205 fn visit_pat(&mut self, p: &ast::Pat) {
206 match p.kind {
207 PatKind::Ident(_, ref spannedident, _) => {
208 self.ident_points.push(spannedident.span.into());
209 }
210 _ => {
211 visit::walk_pat(self, p);
212 }
213 }
214 }
215 }
216
217 pub struct FnArgVisitor {
218 idents: Vec<(Pat, Option<Ty>, ByteRange)>,
219 generics: GenericsArgs,
220 scope: Scope,
221 offset: i32,
222 }
223
224 impl<'ast> visit::Visitor<'ast> for FnArgVisitor {
visit_fn(&mut self, fk: visit::FnKind<'_>, _: source_map::Span, _: ast::NodeId)225 fn visit_fn(&mut self, fk: visit::FnKind<'_>, _: source_map::Span, _: ast::NodeId) {
226 let fd = match fk {
227 visit::FnKind::Fn(_, _, ref fn_sig, _, _) => &*fn_sig.decl,
228 visit::FnKind::Closure(ref fn_decl, _) => fn_decl,
229 };
230 debug!("[FnArgVisitor::visit_fn] inputs: {:?}", fd.inputs);
231 self.idents = fd
232 .inputs
233 .iter()
234 .map(|arg| {
235 debug!("[FnArgTypeVisitor::visit_fn] type {:?} was found", arg.ty);
236 let pat = Pat::from_ast(&arg.pat.kind, &self.scope);
237 let ty = Ty::from_ast(&arg.ty, &self.scope);
238 let source_map::BytePos(lo) = arg.pat.span.lo();
239 let source_map::BytePos(hi) = arg.ty.span.hi();
240 (pat, ty, ByteRange::new(lo, hi))
241 })
242 .collect();
243 }
visit_generics(&mut self, g: &'ast ast::Generics)244 fn visit_generics(&mut self, g: &'ast ast::Generics) {
245 let generics = GenericsArgs::from_generics(g, &self.scope.filepath, self.offset);
246 self.generics.extend(generics);
247 }
248 }
249
point_is_in_span(point: BytePos, span: &Span) -> bool250 fn point_is_in_span(point: BytePos, span: &Span) -> bool {
251 let point: u32 = point.0 as u32;
252 let (lo, hi) = destruct_span(*span);
253 point >= lo && point < hi
254 }
255
256 // The point must point to an ident within the pattern.
destructure_pattern_to_ty( pat: &ast::Pat, point: BytePos, ty: &Ty, scope: &Scope, session: &Session<'_>, ) -> Option<Ty>257 fn destructure_pattern_to_ty(
258 pat: &ast::Pat,
259 point: BytePos,
260 ty: &Ty,
261 scope: &Scope,
262 session: &Session<'_>,
263 ) -> Option<Ty> {
264 debug!(
265 "destructure_pattern_to_ty point {:?} ty {:?} pat: {:?}",
266 point, ty, pat.kind
267 );
268 match pat.kind {
269 PatKind::Ident(_, ref spannedident, _) => {
270 if point_is_in_span(point, &spannedident.span) {
271 debug!("destructure_pattern_to_ty matched an ident!");
272 Some(ty.clone())
273 } else {
274 panic!(
275 "Expecting the point to be in the patident span. pt: {:?}",
276 point
277 );
278 }
279 }
280 PatKind::Tuple(ref tuple_elements) => match *ty {
281 Ty::Tuple(ref typeelems) => {
282 for (i, p) in tuple_elements.iter().enumerate() {
283 if !point_is_in_span(point, &p.span) {
284 continue;
285 }
286 if let Some(ref ty) = typeelems[i] {
287 return destructure_pattern_to_ty(p, point, ty, scope, session);
288 }
289 }
290 None
291 }
292 _ => panic!("Expecting TyTuple"),
293 },
294 PatKind::TupleStruct(ref path, ref children) => {
295 let m = resolve_ast_path(path, &scope.filepath, scope.point, session)?;
296 let contextty = path_to_match(ty.clone(), session);
297 for (i, p) in children.iter().enumerate() {
298 if point_is_in_span(point, &p.span) {
299 return typeinf::get_tuplestruct_field_type(i, &m, session)
300 .and_then(|ty| {
301 // if context ty is a match, use its generics
302 if let Some(Ty::Match(ref contextm)) = contextty {
303 path_to_match_including_generics(
304 ty,
305 contextm.to_generics(),
306 session,
307 )
308 } else {
309 path_to_match(ty, session)
310 }
311 })
312 .and_then(|ty| destructure_pattern_to_ty(p, point, &ty, scope, session));
313 }
314 }
315 None
316 }
317 PatKind::Struct(ref path, ref children, _) => {
318 let m = resolve_ast_path(path, &scope.filepath, scope.point, session)?;
319 let contextty = path_to_match(ty.clone(), session);
320 for child in children {
321 if point_is_in_span(point, &child.span) {
322 return typeinf::get_struct_field_type(&child.ident.name.as_str(), &m, session)
323 .and_then(|ty| {
324 if let Some(Ty::Match(ref contextm)) = contextty {
325 path_to_match_including_generics(
326 ty,
327 contextm.to_generics(),
328 session,
329 )
330 } else {
331 path_to_match(ty, session)
332 }
333 })
334 .and_then(|ty| {
335 destructure_pattern_to_ty(&child.pat, point, &ty, scope, session)
336 });
337 }
338 }
339 None
340 }
341 _ => {
342 debug!("Could not destructure pattern {:?}", pat);
343 None
344 }
345 }
346 }
347
348 struct LetTypeVisitor<'c, 's> {
349 scope: Scope,
350 session: &'s Session<'c>,
351 pos: BytePos, // pos is relative to the srctxt, scope is global
352 result: Option<Ty>,
353 }
354
355 impl<'c, 's, 'ast> visit::Visitor<'ast> for LetTypeVisitor<'c, 's> {
visit_local(&mut self, local: &ast::Local)356 fn visit_local(&mut self, local: &ast::Local) {
357 let ty = match &local.ty {
358 Some(annon) => Ty::from_ast(&*annon, &self.scope),
359 None => local.init.as_ref().and_then(|initexpr| {
360 debug!("[LetTypeVisitor] initexpr is {:?}", initexpr.kind);
361 let mut v = ExprTypeVisitor::new(self.scope.clone(), self.session);
362 v.visit_expr(initexpr);
363 v.result
364 }),
365 };
366 debug!("[LetTypeVisitor] ty is {:?}. pos is {:?}", ty, self.pos);
367 self.result = ty
368 .and_then(|ty| {
369 destructure_pattern_to_ty(&local.pat, self.pos, &ty, &self.scope, self.session)
370 })
371 .and_then(|ty| path_to_match(ty, self.session));
372 }
373 }
374
375 struct MatchTypeVisitor<'c, 's> {
376 scope: Scope,
377 session: &'s Session<'c>,
378 pos: BytePos, // pos is relative to the srctxt, scope is global
379 result: Option<Ty>,
380 }
381
382 impl<'c, 's, 'ast> visit::Visitor<'ast> for MatchTypeVisitor<'c, 's> {
visit_expr(&mut self, ex: &ast::Expr)383 fn visit_expr(&mut self, ex: &ast::Expr) {
384 if let ExprKind::Match(ref subexpression, ref arms) = ex.kind {
385 debug!("PHIL sub expr is {:?}", subexpression);
386
387 let mut v = ExprTypeVisitor::new(self.scope.clone(), self.session);
388 v.visit_expr(subexpression);
389
390 debug!("PHIL sub type is {:?}", v.result);
391
392 for arm in arms {
393 if !point_is_in_span(self.pos, &arm.pat.span) {
394 continue;
395 }
396 debug!("PHIL point is in pattern |{:?}|", arm.pat);
397 self.result = v
398 .result
399 .as_ref()
400 .and_then(|ty| {
401 destructure_pattern_to_ty(&arm.pat, self.pos, ty, &self.scope, self.session)
402 })
403 .and_then(|ty| path_to_match(ty, self.session));
404 }
405 }
406 }
407 }
408
resolve_ast_path( path: &ast::Path, filepath: &Path, pos: BytePos, session: &Session<'_>, ) -> Option<Match>409 fn resolve_ast_path(
410 path: &ast::Path,
411 filepath: &Path,
412 pos: BytePos,
413 session: &Session<'_>,
414 ) -> Option<Match> {
415 let scope = Scope::new(filepath.to_owned(), pos);
416 let path = RacerPath::from_ast(path, &scope);
417 nameres::resolve_path_with_primitive(
418 &path,
419 filepath,
420 pos,
421 core::SearchType::ExactMatch,
422 core::Namespace::Path,
423 session,
424 )
425 .into_iter()
426 .nth(0)
427 }
428
path_to_match(ty: Ty, session: &Session<'_>) -> Option<Ty>429 fn path_to_match(ty: Ty, session: &Session<'_>) -> Option<Ty> {
430 match ty {
431 Ty::PathSearch(paths) => {
432 find_type_match(&paths.path, &paths.filepath, paths.point, session).map(Ty::Match)
433 }
434 Ty::RefPtr(ty, _) => path_to_match(*ty, session),
435 _ => Some(ty),
436 }
437 }
438
find_type_match( path: &RacerPath, fpath: &Path, pos: BytePos, session: &Session<'_>, ) -> Option<Match>439 pub(crate) fn find_type_match(
440 path: &RacerPath,
441 fpath: &Path,
442 pos: BytePos,
443 session: &Session<'_>,
444 ) -> Option<Match> {
445 debug!("find_type_match {:?}, {:?}", path, fpath);
446 let mut res = nameres::resolve_path_with_primitive(
447 path,
448 fpath,
449 pos,
450 core::SearchType::ExactMatch,
451 core::Namespace::Type,
452 session,
453 )
454 .into_iter()
455 .nth(0)
456 .and_then(|m| match m.mtype {
457 MatchType::Type => typeinf::get_type_of_typedef(&m, session),
458 _ => Some(m),
459 })?;
460 // TODO: 'Type' support
461 // if res is Enum/Struct and has a generic type paramter, let's resolve it.
462 for (param, typ) in res.generics_mut().zip(path.generic_types()) {
463 param.resolve(typ.to_owned());
464 }
465 Some(res)
466 }
467
468 struct ExprTypeVisitor<'c, 's> {
469 scope: Scope,
470 session: &'s Session<'c>,
471 // what we have before calling typeinf::get_type_of_match
472 path_match: Option<Match>,
473 result: Option<Ty>,
474 }
475
476 impl<'c: 's, 's> ExprTypeVisitor<'c, 's> {
new(scope: Scope, session: &'s Session<'c>) -> Self477 fn new(scope: Scope, session: &'s Session<'c>) -> Self {
478 ExprTypeVisitor {
479 scope,
480 session,
481 path_match: None,
482 result: None,
483 }
484 }
same_scope(&self) -> Self485 fn same_scope(&self) -> Self {
486 Self {
487 scope: self.scope.clone(),
488 session: self.session,
489 path_match: None,
490 result: None,
491 }
492 }
493 }
494
495 impl<'c, 's, 'ast> visit::Visitor<'ast> for ExprTypeVisitor<'c, 's> {
visit_expr(&mut self, expr: &ast::Expr)496 fn visit_expr(&mut self, expr: &ast::Expr) {
497 debug!(
498 "ExprTypeVisitor::visit_expr {:?}(kind: {:?})",
499 expr, expr.kind
500 );
501 //walk_expr(self, ex, e)
502 match expr.kind {
503 ExprKind::Unary(_, ref expr) | ExprKind::AddrOf(_, _, ref expr) => {
504 self.visit_expr(expr);
505 }
506 ExprKind::Path(_, ref path) => {
507 let source_map::BytePos(lo) = path.span.lo();
508 self.result = resolve_ast_path(
509 path,
510 &self.scope.filepath,
511 self.scope.point + lo.into(),
512 self.session,
513 )
514 .and_then(|m| {
515 let msrc = self.session.load_source_file(&m.filepath);
516 self.path_match = Some(m.clone());
517 typeinf::get_type_of_match(m, msrc.as_src(), self.session)
518 });
519 }
520 ExprKind::Call(ref callee_expression, ref caller_expr) => {
521 self.visit_expr(callee_expression);
522 self.result = self.result.take().and_then(|m| {
523 if let Ty::Match(mut m) = m {
524 match m.mtype {
525 MatchType::Function => {
526 typeinf::get_return_type_of_function(&m, &m, self.session)
527 .and_then(|ty| path_to_match(ty, self.session))
528 }
529 MatchType::Method(ref gen) => {
530 let mut return_ty = typeinf::get_return_type_of_function(&m, &m, self.session);
531 // Account for already resolved generics if the return type is Self
532 // (in which case we return bare type as found in the `impl` header)
533 if let (Some(Ty::Match(ref mut m)), Some(gen)) = (&mut return_ty, gen) {
534 for (type_param, arg) in m.generics_mut().zip(gen.args()) {
535 if let Some(resolved) = arg.resolved() {
536 type_param.resolve(resolved.clone());
537 }
538 }
539 }
540 return_ty.and_then(
541 |ty| {
542 path_to_match_including_generics(
543 ty,
544 gen.as_ref().map(AsRef::as_ref),
545 self.session,
546 )
547 },
548 )
549 }
550 // if we find tuple struct / enum variant, try to resolve its generics name
551 MatchType::Struct(ref mut gen)
552 | MatchType::Enum(ref mut gen)
553 | MatchType::Union(ref mut gen) => {
554 if gen.is_empty() {
555 return Some(Ty::Match(m));
556 }
557 let tuple_fields = match self.path_match {
558 Some(ref m) => typeinf::get_tuplestruct_fields(m, self.session),
559 None => return Some(Ty::Match(m)),
560 };
561 // search what is in callee e.g. Some(String::new()<-) for generics
562 for ((_, _, ty), expr) in tuple_fields.into_iter().zip(caller_expr)
563 {
564 let ty = try_continue!(ty).dereference();
565 if let Ty::PathSearch(paths) = ty {
566 let (id, _) =
567 try_continue!(gen.search_param_by_path(&paths.path));
568 let mut visitor = self.same_scope();
569 visitor.visit_expr(expr);
570 if let Some(ty) = visitor.result {
571 gen.0[id].resolve(ty.dereference());
572 }
573 }
574 }
575 Some(Ty::Match(m))
576 }
577 MatchType::TypeParameter(ref traitbounds)
578 if traitbounds.has_closure() =>
579 {
580 let mut output = None;
581 if let Some(path_search) = traitbounds.get_closure() {
582 for seg in path_search.path.segments.iter() {
583 if seg.output.is_some() {
584 output = seg.output.clone();
585 break;
586 }
587 }
588 }
589 output
590 }
591 _ => {
592 debug!(
593 "ExprTypeVisitor: Cannot handle ExprCall of {:?} type",
594 m.mtype
595 );
596 None
597 }
598 }
599 } else {
600 None
601 }
602 });
603 }
604 ExprKind::Struct(ref struct_expr) => {
605 let ast::StructExpr { ref path, .. } = **struct_expr;
606 let pathvec = RacerPath::from_ast(path, &self.scope);
607 self.result = find_type_match(
608 &pathvec,
609 &self.scope.filepath,
610 self.scope.point,
611 self.session,
612 )
613 .map(Ty::Match);
614 }
615 ExprKind::MethodCall(ref method_def, ref arguments, _) => {
616 let methodname = method_def.ident.name.as_str();
617 debug!("method call ast name {}", methodname);
618
619 // arguments[0] is receiver(e.g. self)
620 let objexpr = &arguments[0];
621 self.visit_expr(objexpr);
622 let result = self.result.take();
623 let get_method_output_ty = |contextm: Match| {
624 let matching_methods = nameres::search_for_fields_and_methods(
625 contextm.clone(),
626 &methodname,
627 core::SearchType::ExactMatch,
628 true,
629 self.session,
630 );
631 matching_methods
632 .into_iter()
633 .filter_map(|method| {
634 let ty = typeinf::get_return_type_of_function(
635 &method,
636 &contextm,
637 self.session,
638 )?;
639 path_to_match_including_generics(
640 ty,
641 contextm.to_generics(),
642 self.session,
643 )
644 })
645 .nth(0)
646 };
647 self.result = result.and_then(|ty| {
648 ty.resolve_as_field_match(self.session)
649 .and_then(get_method_output_ty)
650 });
651 }
652 ExprKind::Field(ref subexpression, spannedident) => {
653 let fieldname = spannedident.name.to_string();
654 debug!("exprfield {}", fieldname);
655 self.visit_expr(subexpression);
656 let result = self.result.take();
657 let match_to_field_ty = |structm: Match| {
658 typeinf::get_struct_field_type(&fieldname, &structm, self.session).and_then(
659 |fieldtypepath| {
660 find_type_match_including_generics(
661 fieldtypepath,
662 &structm.filepath,
663 structm.point,
664 &structm,
665 self.session,
666 )
667 },
668 )
669 };
670 self.result = result.and_then(|ty| {
671 ty.resolve_as_field_match(self.session)
672 .and_then(match_to_field_ty)
673 });
674 }
675 ExprKind::Tup(ref exprs) => {
676 let mut v = Vec::new();
677 for expr in exprs {
678 self.visit_expr(expr);
679 v.push(self.result.take());
680 }
681 self.result = Some(Ty::Tuple(v));
682 }
683 ExprKind::Lit(ref lit) => self.result = Ty::from_lit(lit),
684 ExprKind::Try(ref expr) => {
685 self.visit_expr(&expr);
686 debug!("ExprKind::Try result: {:?} expr: {:?}", self.result, expr);
687 self.result = if let Some(&Ty::Match(ref m)) = self.result.as_ref() {
688 // HACK for speed up (kngwyu)
689 // Yeah there're many corner cases but it'll work well in most cases
690 if m.matchstr == "Result" || m.matchstr == "Option" {
691 debug!("Option or Result: {:?}", m);
692 m.resolved_generics().next().map(|x| x.to_owned())
693 } else {
694 debug!("Unable to desugar Try expression; type was {:?}", m);
695 None
696 }
697 } else {
698 None
699 };
700 }
701 ExprKind::Match(_, ref arms) => {
702 debug!("match expr");
703
704 for arm in arms {
705 self.visit_expr(&arm.body);
706
707 // All match arms need to return the same result, so if we found a result
708 // we can end the search.
709 if self.result.is_some() {
710 break;
711 }
712 }
713 }
714 ExprKind::If(_, ref block, ref else_block) => {
715 debug!("if/iflet expr");
716 if let Some(stmt) = block.stmts.last() {
717 visit::walk_stmt(self, stmt);
718 }
719 if self.result.is_some() {
720 return;
721 }
722 // if the block does not resolve to a type, try the else block
723 if let Some(expr) = else_block {
724 self.visit_expr(expr);
725 }
726 }
727 ExprKind::Block(ref block, ref _label) => {
728 debug!("block expr");
729 if let Some(stmt) = block.stmts.last() {
730 visit::walk_stmt(self, stmt);
731 }
732 }
733 ExprKind::Index(ref body, ref _index) => {
734 self.visit_expr(body);
735 // TODO(kngwyu) now we don't have support for literal so don't parse index
736 // but in the future, we should handle index's type
737 self.result = self
738 .result
739 .take()
740 .and_then(|ty| typeinf::get_type_of_indexed_value(ty, self.session));
741 }
742 ExprKind::Array(ref exprs) => {
743 for expr in exprs {
744 self.visit_expr(expr);
745 if self.result.is_some() {
746 self.result = self
747 .result
748 .take()
749 .map(|ty| Ty::Array(Box::new(ty), format!("{}", exprs.len())));
750 break;
751 }
752 }
753 if self.result.is_none() {
754 self.result = Some(Ty::Array(Box::new(Ty::Unsupported), String::new()));
755 }
756 }
757 ExprKind::MacCall(ref m) => {
758 if let Some(name) = m.path.segments.last().map(|seg| seg.ident) {
759 // use some ad-hoc rules
760 if name.as_str() == "vec" {
761 let path = RacerPath::from_iter(
762 true,
763 ["std", "vec", "Vec"].iter().map(|s| s.to_string()),
764 );
765 self.result = find_type_match(
766 &path,
767 &self.scope.filepath,
768 self.scope.point,
769 self.session,
770 )
771 .map(Ty::Match);
772 }
773 }
774 }
775 ExprKind::Binary(bin, ref left, ref right) => {
776 self.visit_expr(left);
777 let type_match = match self.result.take() {
778 Some(Ty::Match(m)) => m,
779 Some(Ty::PathSearch(ps)) => match ps.resolve_as_match(self.session) {
780 Some(m) => m,
781 _ => {
782 return;
783 }
784 },
785 _ => {
786 return;
787 }
788 };
789
790 self.visit_expr(right);
791 let right_expr_type = match self.result.take() {
792 Some(Ty::Match(m)) => Some(m.matchstr),
793 Some(Ty::PathSearch(ps)) => {
794 ps.resolve_as_match(self.session).map(|m| m.matchstr)
795 }
796 _ => None,
797 };
798 self.result = nameres::resolve_binary_expr_type(
799 &type_match,
800 bin.node,
801 right_expr_type.as_ref().map(|s| s.as_str()),
802 self.session,
803 );
804 }
805 _ => {
806 debug!("- Could not match expr node type: {:?}", expr.kind);
807 }
808 };
809 }
810 /// Just do nothing if we see a macro, but also prevent the panic! in the default impl.
visit_mac_call(&mut self, _mac: &ast::MacCall)811 fn visit_mac_call(&mut self, _mac: &ast::MacCall) {}
812 }
813
814 // gets generics info from the context match
path_to_match_including_generics( mut ty: Ty, generics: Option<&GenericsArgs>, session: &Session<'_>, ) -> Option<Ty>815 fn path_to_match_including_generics(
816 mut ty: Ty,
817 generics: Option<&GenericsArgs>,
818 session: &Session<'_>,
819 ) -> Option<Ty> {
820 if let Some(gen) = generics {
821 ty = ty.replace_by_generics(gen);
822 }
823 match ty {
824 Ty::PathSearch(paths) => {
825 let fieldtypepath = &paths.path;
826 find_type_match(&fieldtypepath, &paths.filepath, paths.point, session).map(Ty::Match)
827 }
828 _ => Some(ty),
829 }
830 }
831
find_type_match_including_generics( fieldtype: Ty, filepath: &Path, pos: BytePos, structm: &Match, session: &Session<'_>, ) -> Option<Ty>832 fn find_type_match_including_generics(
833 fieldtype: Ty,
834 filepath: &Path,
835 pos: BytePos,
836 structm: &Match,
837 session: &Session<'_>,
838 ) -> Option<Ty> {
839 assert_eq!(&structm.filepath, filepath);
840 let fieldtypepath = match fieldtype {
841 Ty::PathSearch(paths) => paths.path,
842 Ty::RefPtr(ty, _) => match ty.dereference() {
843 Ty::PathSearch(paths) => paths.path,
844 Ty::Match(m) => return Some(Ty::Match(m)),
845 _ => return None,
846 },
847 // already resolved
848 Ty::Match(m) => return Some(Ty::Match(m)),
849 _ => {
850 return None;
851 }
852 };
853 let generics = match &structm.mtype {
854 MatchType::Struct(gen) => gen,
855 _ => return None,
856 };
857 if fieldtypepath.segments.len() == 1 {
858 // could be a generic arg! - try and resolve it
859 if let Some((_, param)) = generics.search_param_by_path(&fieldtypepath) {
860 if let Some(res) = param.resolved() {
861 return Some(res.to_owned());
862 }
863 let mut m = param.to_owned().into_match();
864 m.local = structm.local;
865 return Some(Ty::Match(m));
866 }
867 }
868
869 find_type_match(&fieldtypepath, filepath, pos, session).map(Ty::Match)
870 }
871
872 struct StructVisitor {
873 pub scope: Scope,
874 pub fields: Vec<(String, ByteRange, Option<Ty>)>,
875 }
876
877 impl<'ast> visit::Visitor<'ast> for StructVisitor {
visit_variant_data(&mut self, struct_definition: &ast::VariantData)878 fn visit_variant_data(&mut self, struct_definition: &ast::VariantData) {
879 for field in struct_definition.fields() {
880 let ty = Ty::from_ast(&field.ty, &self.scope);
881 let name = match field.ident {
882 Some(ref ident) => ident.to_string(),
883 // name unnamed field by its ordinal, since self.0 works
884 None => format!("{}", self.fields.len()),
885 };
886 self.fields.push((name, field.span.into(), ty));
887 }
888 }
889 }
890
891 #[derive(Debug)]
892 pub struct TypeVisitor<'s> {
893 pub name: Option<String>,
894 pub type_: Option<Ty>,
895 scope: &'s Scope,
896 }
897
898 impl<'ast, 's> visit::Visitor<'ast> for TypeVisitor<'s> {
visit_item(&mut self, item: &ast::Item)899 fn visit_item(&mut self, item: &ast::Item) {
900 if let ItemKind::TyAlias(ref ty_kind) = item.kind {
901 if let Some(ref ty) = ty_kind.3 {
902 self.name = Some(item.ident.name.to_string());
903 self.type_ = Ty::from_ast(&ty, self.scope);
904 debug!("typevisitor type is {:?}", self.type_);
905 }
906 }
907 }
908 }
909
910 pub struct TraitVisitor {
911 pub name: Option<String>,
912 }
913
914 impl<'ast> visit::Visitor<'ast> for TraitVisitor {
visit_item(&mut self, item: &ast::Item)915 fn visit_item(&mut self, item: &ast::Item) {
916 if let ItemKind::Trait(..) = item.kind {
917 self.name = Some(item.ident.name.to_string());
918 }
919 }
920 }
921
922 #[derive(Debug)]
923 pub struct ImplVisitor<'p> {
924 pub result: Option<ImplHeader>,
925 filepath: &'p Path,
926 offset: BytePos,
927 block_start: BytePos, // the point { appears
928 local: bool,
929 }
930
931 impl<'p> ImplVisitor<'p> {
new(filepath: &'p Path, offset: BytePos, local: bool, block_start: BytePos) -> Self932 fn new(filepath: &'p Path, offset: BytePos, local: bool, block_start: BytePos) -> Self {
933 ImplVisitor {
934 result: None,
935 filepath,
936 offset,
937 block_start,
938 local,
939 }
940 }
941 }
942
943 impl<'ast, 'p> visit::Visitor<'ast> for ImplVisitor<'p> {
visit_item(&mut self, item: &ast::Item)944 fn visit_item(&mut self, item: &ast::Item) {
945 if let ItemKind::Impl(ref impl_kind) = item.kind {
946 let ast::ImplKind {
947 ref generics,
948 ref of_trait,
949 ref self_ty,
950 ..
951 } = **impl_kind;
952 let impl_start = self.offset + get_span_start(item.span).into();
953 self.result = ImplHeader::new(
954 generics,
955 self.filepath,
956 of_trait,
957 self_ty,
958 self.offset,
959 self.local,
960 impl_start,
961 self.block_start,
962 );
963 }
964 }
965 }
966
967 pub struct ExternCrateVisitor {
968 pub name: Option<String>,
969 pub realname: Option<String>,
970 }
971
972 impl<'ast> visit::Visitor<'ast> for ExternCrateVisitor {
visit_item(&mut self, item: &ast::Item)973 fn visit_item(&mut self, item: &ast::Item) {
974 if let ItemKind::ExternCrate(ref optional_s) = item.kind {
975 self.name = Some(item.ident.name.to_string());
976 if let Some(ref istr) = *optional_s {
977 self.realname = Some(istr.to_string());
978 }
979 }
980 }
visit_mac_call(&mut self, _mac: &ast::MacCall)981 fn visit_mac_call(&mut self, _mac: &ast::MacCall) {}
982 }
983
984 #[derive(Debug)]
985 struct GenericsVisitor<P> {
986 result: GenericsArgs,
987 filepath: P,
988 }
989
990 impl<'ast, P: AsRef<Path>> visit::Visitor<'ast> for GenericsVisitor<P> {
visit_generics(&mut self, g: &ast::Generics)991 fn visit_generics(&mut self, g: &ast::Generics) {
992 let path = &self.filepath;
993 if !self.result.0.is_empty() {
994 warn!("[visit_generics] called for multiple generics!");
995 }
996 self.result.extend(GenericsArgs::from_generics(g, path, 0));
997 }
998 }
999
1000 pub struct EnumVisitor {
1001 pub name: String,
1002 pub values: Vec<(String, BytePos)>,
1003 }
1004
1005 impl<'ast> visit::Visitor<'ast> for EnumVisitor {
visit_item(&mut self, i: &ast::Item)1006 fn visit_item(&mut self, i: &ast::Item) {
1007 if let ItemKind::Enum(ref enum_definition, _) = i.kind {
1008 self.name = i.ident.name.to_string();
1009 let (point1, point2) = destruct_span(i.span);
1010 debug!("name point is {} {}", point1, point2);
1011
1012 for variant in &enum_definition.variants {
1013 let source_map::BytePos(point) = variant.span.lo();
1014 self.values.push((variant.ident.to_string(), point.into()));
1015 }
1016 }
1017 }
1018 }
1019
1020 #[derive(Clone, Debug)]
1021 pub struct StaticVisitor {
1022 pub ty: Option<Ty>,
1023 pub is_mutable: bool,
1024 scope: Scope,
1025 }
1026
1027 impl StaticVisitor {
new(scope: Scope) -> Self1028 fn new(scope: Scope) -> Self {
1029 StaticVisitor {
1030 ty: None,
1031 is_mutable: false,
1032 scope,
1033 }
1034 }
1035 }
1036
1037 impl<'ast> visit::Visitor<'ast> for StaticVisitor {
visit_item(&mut self, i: &ast::Item)1038 fn visit_item(&mut self, i: &ast::Item) {
1039 match i.kind {
1040 ItemKind::Const(_, ref ty, ref _expr) => self.ty = Ty::from_ast(ty, &self.scope),
1041 ItemKind::Static(ref ty, m, ref _expr) => {
1042 self.is_mutable = m == ast::Mutability::Mut;
1043 self.ty = Ty::from_ast(ty, &self.scope);
1044 }
1045 _ => {}
1046 }
1047 }
1048 }
1049
parse_use(s: String) -> UseVisitor1050 pub fn parse_use(s: String) -> UseVisitor {
1051 let mut v = UseVisitor {
1052 path_list: Vec::new(),
1053 contains_glob: false,
1054 };
1055
1056 // visit::walk_crate can be panic so we don't use it here
1057 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1058 v
1059 }
1060
parse_pat_bind_stmt(s: String) -> Vec<ByteRange>1061 pub fn parse_pat_bind_stmt(s: String) -> Vec<ByteRange> {
1062 let mut v = PatBindVisitor {
1063 ident_points: Vec::new(),
1064 };
1065 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1066 v.ident_points
1067 }
1068
parse_struct_fields(s: String, scope: Scope) -> Vec<(String, ByteRange, Option<Ty>)>1069 pub fn parse_struct_fields(s: String, scope: Scope) -> Vec<(String, ByteRange, Option<Ty>)> {
1070 let mut v = StructVisitor {
1071 scope,
1072 fields: Vec::new(),
1073 };
1074 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1075 v.fields
1076 }
1077
parse_impl( s: String, path: &Path, offset: BytePos, local: bool, scope_start: BytePos, ) -> Option<ImplHeader>1078 pub fn parse_impl(
1079 s: String,
1080 path: &Path,
1081 offset: BytePos,
1082 local: bool,
1083 scope_start: BytePos,
1084 ) -> Option<ImplHeader> {
1085 let mut v = ImplVisitor::new(path, offset, local, scope_start);
1086 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1087 v.result
1088 }
1089
parse_trait(s: String) -> TraitVisitor1090 pub fn parse_trait(s: String) -> TraitVisitor {
1091 let mut v = TraitVisitor { name: None };
1092 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1093 v
1094 }
1095
1096 /// parse traits and collect inherited traits as TraitBounds
parse_inherited_traits<P: AsRef<Path>>( s: String, filepath: P, offset: i32, ) -> Option<TraitBounds>1097 pub fn parse_inherited_traits<P: AsRef<Path>>(
1098 s: String,
1099 filepath: P,
1100 offset: i32,
1101 ) -> Option<TraitBounds> {
1102 let mut v = InheritedTraitsVisitor {
1103 result: None,
1104 file_path: filepath,
1105 offset: offset,
1106 };
1107 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1108 v.result
1109 }
1110
parse_generics(s: String, filepath: &Path) -> GenericsArgs1111 pub fn parse_generics(s: String, filepath: &Path) -> GenericsArgs {
1112 let mut v = GenericsVisitor {
1113 result: GenericsArgs::default(),
1114 filepath: filepath,
1115 };
1116 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1117 v.result
1118 }
1119
parse_type<'s>(s: String, scope: &'s Scope) -> TypeVisitor<'s>1120 pub fn parse_type<'s>(s: String, scope: &'s Scope) -> TypeVisitor<'s> {
1121 let mut v = TypeVisitor {
1122 name: None,
1123 type_: None,
1124 scope,
1125 };
1126 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1127 v
1128 }
1129
parse_fn_args_and_generics( s: String, scope: Scope, offset: i32, ) -> (Vec<(Pat, Option<Ty>, ByteRange)>, GenericsArgs)1130 pub fn parse_fn_args_and_generics(
1131 s: String,
1132 scope: Scope,
1133 offset: i32,
1134 ) -> (Vec<(Pat, Option<Ty>, ByteRange)>, GenericsArgs) {
1135 let mut v = FnArgVisitor {
1136 idents: Vec::new(),
1137 generics: GenericsArgs::default(),
1138 scope,
1139 offset,
1140 };
1141 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1142 (v.idents, v.generics)
1143 }
1144
parse_closure_args(s: String, scope: Scope) -> Vec<(Pat, Option<Ty>, ByteRange)>1145 pub fn parse_closure_args(s: String, scope: Scope) -> Vec<(Pat, Option<Ty>, ByteRange)> {
1146 let mut v = FnArgVisitor {
1147 idents: Vec::new(),
1148 generics: GenericsArgs::default(),
1149 scope,
1150 offset: 0,
1151 };
1152 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1153 v.idents
1154 }
1155
parse_pat_idents(s: String) -> Vec<ByteRange>1156 pub fn parse_pat_idents(s: String) -> Vec<ByteRange> {
1157 let mut v = PatVisitor {
1158 ident_points: Vec::new(),
1159 };
1160 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1161 debug!("ident points are {:?}", v.ident_points);
1162 v.ident_points
1163 }
1164
parse_fn_output(s: String, scope: Scope) -> (Option<Ty>, bool)1165 pub fn parse_fn_output(s: String, scope: Scope) -> (Option<Ty>, bool) {
1166 let mut v = FnOutputVisitor::new(scope);
1167 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1168 let FnOutputVisitor { ty, is_async, .. } = v;
1169 (ty, is_async)
1170 }
1171
parse_extern_crate(s: String) -> ExternCrateVisitor1172 pub fn parse_extern_crate(s: String) -> ExternCrateVisitor {
1173 let mut v = ExternCrateVisitor {
1174 name: None,
1175 realname: None,
1176 };
1177 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1178 v
1179 }
1180
parse_enum(s: String) -> EnumVisitor1181 pub fn parse_enum(s: String) -> EnumVisitor {
1182 let mut v = EnumVisitor {
1183 name: String::new(),
1184 values: Vec::new(),
1185 };
1186 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1187 v
1188 }
1189
parse_static(s: String, scope: Scope) -> StaticVisitor1190 pub fn parse_static(s: String, scope: Scope) -> StaticVisitor {
1191 let mut v = StaticVisitor::new(scope);
1192 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1193 v
1194 }
1195
get_type_of(s: String, fpath: &Path, pos: BytePos, session: &Session<'_>) -> Option<Ty>1196 pub fn get_type_of(s: String, fpath: &Path, pos: BytePos, session: &Session<'_>) -> Option<Ty> {
1197 let startscope = Scope {
1198 filepath: fpath.to_path_buf(),
1199 point: pos,
1200 };
1201
1202 let mut v = ExprTypeVisitor::new(startscope, session);
1203
1204 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1205 v.result
1206 }
1207
1208 // pos points to an ident in the lhs of the stmtstr
get_let_type(s: String, pos: BytePos, scope: Scope, session: &Session<'_>) -> Option<Ty>1209 pub fn get_let_type(s: String, pos: BytePos, scope: Scope, session: &Session<'_>) -> Option<Ty> {
1210 let mut v = LetTypeVisitor {
1211 scope,
1212 session,
1213 pos,
1214 result: None,
1215 };
1216 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1217 v.result
1218 }
1219
get_match_arm_type( s: String, pos: BytePos, scope: Scope, session: &Session<'_>, ) -> Option<Ty>1220 pub fn get_match_arm_type(
1221 s: String,
1222 pos: BytePos,
1223 scope: Scope,
1224 session: &Session<'_>,
1225 ) -> Option<Ty> {
1226 let mut v = MatchTypeVisitor {
1227 scope,
1228 session,
1229 pos,
1230 result: None,
1231 };
1232 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1233 v.result
1234 }
1235
1236 pub struct FnOutputVisitor {
1237 scope: Scope,
1238 pub ty: Option<Ty>,
1239 pub is_async: bool,
1240 }
1241
1242 impl FnOutputVisitor {
new(scope: Scope) -> Self1243 pub(crate) fn new(scope: Scope) -> Self {
1244 FnOutputVisitor {
1245 scope,
1246 ty: None,
1247 is_async: false,
1248 }
1249 }
1250 }
1251
1252 impl<'ast> visit::Visitor<'ast> for FnOutputVisitor {
visit_fn(&mut self, kind: visit::FnKind<'_>, _: source_map::Span, _: ast::NodeId)1253 fn visit_fn(&mut self, kind: visit::FnKind<'_>, _: source_map::Span, _: ast::NodeId) {
1254 let fd = match kind {
1255 visit::FnKind::Fn(_, _, ref fn_sig, _, _) => &*fn_sig.decl,
1256 visit::FnKind::Closure(ref fn_decl, _) => fn_decl,
1257 };
1258 self.is_async = kind
1259 .header()
1260 .map(|header| header.asyncness.is_async())
1261 .unwrap_or(false);
1262 self.ty = match fd.output {
1263 FnRetTy::Ty(ref ty) => Ty::from_ast(ty, &self.scope),
1264 FnRetTy::Default(_) => Some(Ty::Default),
1265 };
1266 }
1267 }
1268
1269 /// Visitor to collect Inherited Traits
1270 pub struct InheritedTraitsVisitor<P> {
1271 /// search result(list of Inherited Traits)
1272 result: Option<TraitBounds>,
1273 /// the file trait appears
1274 file_path: P,
1275 /// thecode point 'trait' statement starts
1276 offset: i32,
1277 }
1278
1279 impl<'ast, P> visit::Visitor<'ast> for InheritedTraitsVisitor<P>
1280 where
1281 P: AsRef<Path>,
1282 {
visit_item(&mut self, item: &ast::Item)1283 fn visit_item(&mut self, item: &ast::Item) {
1284 if let ItemKind::Trait(ref trait_kind) = item.kind {
1285 self.result = Some(TraitBounds::from_generic_bounds(
1286 &trait_kind.3,
1287 &self.file_path,
1288 self.offset,
1289 ));
1290 }
1291 }
1292 }
1293
1294 /// Visitor for for ~ in .. statement
1295 pub(crate) struct ForStmtVisitor<'r, 's> {
1296 pub(crate) for_pat: Option<Pat>,
1297 pub(crate) in_expr: Option<Ty>,
1298 scope: Scope,
1299 session: &'r Session<'s>,
1300 }
1301
1302 impl<'ast, 'r, 's> visit::Visitor<'ast> for ForStmtVisitor<'r, 's> {
visit_expr(&mut self, ex: &'ast ast::Expr)1303 fn visit_expr(&mut self, ex: &'ast ast::Expr) {
1304 if let ExprKind::ForLoop(ref pat, ref expr, _, _) = ex.kind {
1305 let for_pat = Pat::from_ast(&pat.kind, &self.scope);
1306 let mut expr_visitor = ExprTypeVisitor::new(self.scope.clone(), self.session);
1307 expr_visitor.visit_expr(expr);
1308 self.in_expr = expr_visitor.result;
1309 self.for_pat = Some(for_pat);
1310 }
1311 }
1312 }
1313
parse_for_stmt<'r, 's: 'r>( s: String, scope: Scope, session: &'r Session<'s>, ) -> ForStmtVisitor<'r, 's>1314 pub(crate) fn parse_for_stmt<'r, 's: 'r>(
1315 s: String,
1316 scope: Scope,
1317 session: &'r Session<'s>,
1318 ) -> ForStmtVisitor<'r, 's> {
1319 let mut v = ForStmtVisitor {
1320 for_pat: None,
1321 in_expr: None,
1322 scope,
1323 session,
1324 };
1325 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1326 v
1327 }
1328
1329 /// Visitor for if let / while let statement
1330 pub(crate) struct IfLetVisitor<'r, 's> {
1331 pub(crate) let_pat: Option<Pat>,
1332 pub(crate) rh_expr: Option<Ty>,
1333 scope: Scope,
1334 session: &'r Session<'s>,
1335 }
1336
1337 impl<'ast, 'r, 's> visit::Visitor<'ast> for IfLetVisitor<'r, 's> {
visit_expr(&mut self, ex: &'ast ast::Expr)1338 fn visit_expr(&mut self, ex: &'ast ast::Expr) {
1339 match &ex.kind {
1340 ExprKind::If(let_stmt, ..) | ExprKind::While(let_stmt, ..) => {
1341 if let ExprKind::Let(pat, expr) = &let_stmt.kind {
1342 self.let_pat = Some(Pat::from_ast(&pat.kind, &self.scope));
1343 let mut expr_visitor = ExprTypeVisitor::new(self.scope.clone(), self.session);
1344 expr_visitor.visit_expr(expr);
1345 self.rh_expr = expr_visitor.result;
1346 }
1347 }
1348 _ => {}
1349 }
1350 }
1351 }
1352
parse_if_let<'r, 's: 'r>( s: String, scope: Scope, session: &'r Session<'s>, ) -> IfLetVisitor<'r, 's>1353 pub(crate) fn parse_if_let<'r, 's: 'r>(
1354 s: String,
1355 scope: Scope,
1356 session: &'r Session<'s>,
1357 ) -> IfLetVisitor<'r, 's> {
1358 let mut v = IfLetVisitor {
1359 let_pat: None,
1360 rh_expr: None,
1361 scope,
1362 session,
1363 };
1364 with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
1365 v
1366 }
1367