diagnostics.rs 48.3 KB
Newer Older
1
use crate::diagnostics::{ImportSuggestion, TypoSuggestion};
2
use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
3
use crate::late::{LateResolutionVisitor, RibKind};
M
Mark Rousskov 已提交
4 5 6
use crate::path_names_to_string;
use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
7

8 9
use rustc_ast::ast::{self, Expr, ExprKind, Ident, Item, ItemKind, NodeId, Path, Ty, TyKind};
use rustc_ast::util::lev_distance::find_best_match_for_name;
10
use rustc_data_structures::fx::FxHashSet;
11 12
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
13 14 15 16
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::PrimTy;
17
use rustc_session::config::nightly_options;
18
use rustc_span::hygiene::MacroKind;
19
use rustc_span::symbol::{kw, sym};
20
use rustc_span::Span;
21

22
use log::debug;
23

24 25 26 27 28 29 30 31 32
type Res = def::Res<ast::NodeId>;

/// A field or associated item from self type suggested in case of resolution failure.
enum AssocSuggestion {
    Field,
    MethodWithSelf,
    AssocItem,
}

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
crate enum MissingLifetimeSpot<'tcx> {
    Generics(&'tcx hir::Generics<'tcx>),
    HigherRanked { span: Span, span_type: ForLifetimeSpanType },
}

crate enum ForLifetimeSpanType {
    BoundEmpty,
    BoundTail,
    TypeEmpty,
    TypeTail,
}

impl ForLifetimeSpanType {
    crate fn descr(&self) -> &'static str {
        match self {
            Self::BoundEmpty | Self::BoundTail => "bound",
            Self::TypeEmpty | Self::TypeTail => "type",
        }
    }

    crate fn suggestion(&self, sugg: &str) -> String {
        match self {
            Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
            Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
        }
    }
}

impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &'tcx hir::Generics<'tcx> {
    fn into(self) -> MissingLifetimeSpot<'tcx> {
        MissingLifetimeSpot::Generics(self)
    }
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
    namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
}

fn is_self_value(path: &[Segment], namespace: Namespace) -> bool {
    namespace == ValueNS && path.len() == 1 && path[0].ident.name == kw::SelfLower
}

/// Gets the stringified path for an enum from an `ImportSuggestion` for an enum variant.
fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, String) {
    let variant_path = &suggestion.path;
    let variant_path_string = path_names_to_string(variant_path);

    let path_len = suggestion.path.segments.len();
    let enum_path = ast::Path {
        span: suggestion.path.span,
        segments: suggestion.path.segments[0..path_len - 1].to_vec(),
    };
    let enum_path_string = path_names_to_string(&enum_path);

    (variant_path_string, enum_path_string)
}

90
impl<'a> LateResolutionVisitor<'a, '_, '_> {
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    /// Handles error reporting for `smart_resolve_path_fragment` function.
    /// Creates base error and amends it with one short label and possibly some longer helps/notes.
    pub(crate) fn smart_resolve_report_errors(
        &mut self,
        path: &[Segment],
        span: Span,
        source: PathSource<'_>,
        res: Option<Res>,
    ) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
        let ident_span = path.last().map_or(span, |ident| ident.ident.span);
        let ns = source.namespace();
        let is_expected = &|res| source.is_expected(res);
        let is_enum_variant = &|res| {
            if let Res::Def(DefKind::Variant, _) = res { true } else { false }
        };

        // Make the base error.
        let expected = source.descr_expected();
        let path_str = Segment::names_to_string(path);
        let item_str = path.last().unwrap().ident;
E
Esteban Küber 已提交
111
        let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res {
M
Mark Rousskov 已提交
112 113
            (
                format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
114
                format!("not a {}", expected),
115 116
                span,
                match res {
E
Esteban Küber 已提交
117 118
                    Res::Def(DefKind::Fn, _) => {
                        // Verify whether this is a fn call or an Fn used as a type.
M
Mark Rousskov 已提交
119 120 121 122 123 124
                        self.r
                            .session
                            .source_map()
                            .span_to_snippet(span)
                            .map(|snippet| snippet.ends_with(')'))
                            .unwrap_or(false)
E
Esteban Küber 已提交
125
                    }
126 127 128 129
                    Res::Def(
                        DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
                        _,
                    )
M
Mark Rousskov 已提交
130 131 132
                    | Res::SelfCtor(_)
                    | Res::PrimTy(_)
                    | Res::Local(_) => true,
133
                    _ => false,
M
Mark Rousskov 已提交
134 135
                },
            )
136 137 138 139 140 141 142 143
        } else {
            let item_span = path.last().unwrap().ident.span;
            let (mod_prefix, mod_str) = if path.len() == 1 {
                (String::new(), "this scope".to_string())
            } else if path.len() == 2 && path[0].ident.name == kw::PathRoot {
                (String::new(), "the crate root".to_string())
            } else {
                let mod_path = &path[..path.len() - 1];
M
Mark Rousskov 已提交
144 145 146 147 148 149
                let mod_prefix =
                    match self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No) {
                        PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(),
                        _ => None,
                    }
                    .map_or(String::new(), |res| format!("{} ", res.descr()));
150 151
                (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)))
            };
M
Mark Rousskov 已提交
152 153
            (
                format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
154
                format!("not found in {}", mod_str),
155
                item_span,
M
Mark Rousskov 已提交
156 157
                false,
            )
158 159
        };

160
        let code = source.error_code(res.is_some());
161
        let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
162 163 164

        // Emit help message for fake-self from other languages (e.g., `this` in Javascript).
        if ["this", "my"].contains(&&*item_str.as_str())
M
Mark Rousskov 已提交
165 166
            && self.self_value_is_available(path[0].ident.span, span)
        {
167 168 169 170 171 172 173 174 175 176
            err.span_suggestion(
                span,
                "did you mean",
                "self".to_string(),
                Applicability::MaybeIncorrect,
            );
        }

        // Emit special messages for unresolved `Self` and `self`.
        if is_self_type(path, ns) {
177
            err.code(rustc_errors::error_code!(E0411));
178 179
            err.span_label(
                span,
180
                "`Self` is only available in impls, traits, and type definitions".to_string(),
181
            );
182 183 184 185 186
            return (err, Vec::new());
        }
        if is_self_value(path, ns) {
            debug!("smart_resolve_path_fragment: E0424, source={:?}", source);

187
            err.code(rustc_errors::error_code!(E0424));
188
            err.span_label(span, match source {
189 190 191 192
                PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed"
                                   .to_string(),
                _ => "`self` value is a keyword only available in methods with a `self` parameter"
                     .to_string(),
193
            });
E
Esteban Küber 已提交
194
            if let Some(span) = &self.diagnostic_metadata.current_function {
195 196
                err.span_label(*span, "this function doesn't have a `self` parameter");
            }
197 198 199 200 201
            return (err, Vec::new());
        }

        // Try to lookup name in more relaxed fashion for better error reporting.
        let ident = path.last().unwrap().ident;
M
Mark Rousskov 已提交
202 203 204
        let candidates = self
            .r
            .lookup_import_candidates(ident, ns, is_expected)
205 206 207 208 209 210 211 212 213 214
            .drain(..)
            .filter(|ImportSuggestion { did, .. }| {
                match (did, res.and_then(|res| res.opt_def_id())) {
                    (Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
                    _ => true,
                }
            })
            .collect::<Vec<_>>();
        let crate_def_id = DefId::local(CRATE_DEF_INDEX);
        if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
M
Mark Rousskov 已提交
215 216 217 218 219
            let enum_candidates = self.r.lookup_import_candidates(ident, ns, is_enum_variant);
            let mut enum_candidates = enum_candidates
                .iter()
                .map(|suggestion| import_candidate_to_enum_paths(&suggestion))
                .collect::<Vec<_>>();
220 221 222 223 224 225 226 227 228
            enum_candidates.sort();

            if !enum_candidates.is_empty() {
                // Contextualize for E0412 "cannot find type", but don't belabor the point
                // (that it's a variant) for E0573 "expected type, found variant".
                let preamble = if res.is_none() {
                    let others = match enum_candidates.len() {
                        1 => String::new(),
                        2 => " and 1 other".to_owned(),
M
Mark Rousskov 已提交
229
                        n => format!(" and {} others", n),
230
                    };
M
Mark Rousskov 已提交
231
                    format!("there is an enum variant `{}`{}; ", enum_candidates[0].0, others)
232 233 234 235 236 237 238 239
                } else {
                    String::new()
                };
                let msg = format!("{}try using the variant's enum", preamble);

                err.span_suggestions(
                    span,
                    &msg,
M
Mark Rousskov 已提交
240 241
                    enum_candidates
                        .into_iter()
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
                        .map(|(_variant_path, enum_ty_path)| enum_ty_path)
                        // Variants re-exported in prelude doesn't mean `prelude::v1` is the
                        // type name!
                        // FIXME: is there a more principled way to do this that
                        // would work for other re-exports?
                        .filter(|enum_ty_path| enum_ty_path != "std::prelude::v1")
                        // Also write `Option` rather than `std::prelude::v1::Option`.
                        .map(|enum_ty_path| {
                            // FIXME #56861: DRY-er prelude filtering.
                            enum_ty_path.trim_start_matches("std::prelude::v1::").to_owned()
                        }),
                    Applicability::MachineApplicable,
                );
            }
        }
        if path.len() == 1 && self.self_type_is_available(span) {
            if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
                let self_is_available = self.self_value_is_available(path[0].ident.span, span);
                match candidate {
                    AssocSuggestion::Field => {
                        if self_is_available {
                            err.span_suggestion(
                                span,
                                "you might have meant to use the available field",
                                format!("self.{}", path_str),
                                Applicability::MachineApplicable,
                            );
                        } else {
M
Mark Rousskov 已提交
270
                            err.span_label(span, "a field by this name exists in `Self`");
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
                        }
                    }
                    AssocSuggestion::MethodWithSelf if self_is_available => {
                        err.span_suggestion(
                            span,
                            "try",
                            format!("self.{}", path_str),
                            Applicability::MachineApplicable,
                        );
                    }
                    AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
                        err.span_suggestion(
                            span,
                            "try",
                            format!("Self::{}", path_str),
                            Applicability::MachineApplicable,
                        );
                    }
                }
                return (err, candidates);
            }
292

293 294 295
            // If the first argument in call is `self` suggest calling a method.
            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
                let mut args_snippet = String::new();
296 297 298 299 300 301
                if let Some(args_span) = args_span {
                    if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) {
                        args_snippet = snippet;
                    }
                }

302
                err.span_suggestion(
303
                    call_span,
304
                    &format!("try calling `{}` as a method", ident),
305
                    format!("self.{}({})", path_str, args_snippet),
306 307 308 309
                    Applicability::MachineApplicable,
                );
                return (err, candidates);
            }
310 311 312
        }

        // Try Levenshtein algorithm.
313 314
        let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected, span);
        let levenshtein_worked = self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
315 316 317

        // Try context-dependent help if relaxed lookup didn't work.
        if let Some(res) = res {
318 319 320 321 322 323 324 325
            if self.smart_resolve_context_dependent_help(
                &mut err,
                span,
                source,
                res,
                &path_str,
                &fallback_label,
            ) {
326 327 328 329 330 331 332 333
                return (err, candidates);
            }
        }

        // Fallback label.
        if !levenshtein_worked {
            err.span_label(base_span, fallback_label);
            self.type_ascription_suggestion(&mut err, base_span);
E
Esteban Küber 已提交
334
            match self.diagnostic_metadata.current_let_binding {
M
Mark Rousskov 已提交
335
                Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
E
Esteban Küber 已提交
336 337 338 339 340 341
                    err.span_suggestion_short(
                        pat_sp.between(ty_sp),
                        "use `=` if you meant to assign",
                        " = ".to_string(),
                        Applicability::MaybeIncorrect,
                    );
342
                }
E
Esteban Küber 已提交
343
                _ => {}
344
            }
345 346 347 348
        }
        (err, candidates)
    }

349 350 351 352 353
    /// Check if the source is call expression and the first argument is `self`. If true,
    /// return the span of whole call and the span for all arguments expect the first one (`self`).
    fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
        let mut has_self_arg = None;
        if let PathSource::Expr(parent) = source {
J
Janusz Marcinkiewicz 已提交
354
            match &parent?.kind {
355
                ExprKind::Call(_, args) if !args.is_empty() => {
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
                    let mut expr_kind = &args[0].kind;
                    loop {
                        match expr_kind {
                            ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
                                if arg_name.segments[0].ident.name == kw::SelfLower {
                                    let call_span = parent.unwrap().span;
                                    let tail_args_span = if args.len() > 1 {
                                        Some(Span::new(
                                            args[1].span.lo(),
                                            args.last().unwrap().span.hi(),
                                            call_span.ctxt(),
                                        ))
                                    } else {
                                        None
                                    };
                                    has_self_arg = Some((call_span, tail_args_span));
                                }
                                break;
                            }
                            ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
                            _ => break,
                        }
                    }
                }
                _ => (),
            }
        };
383
        has_self_arg
384 385
    }

386
    fn followed_by_brace(&self, span: Span) -> (bool, Option<Span>) {
387 388 389 390
        // HACK(estebank): find a better way to figure out that this was a
        // parser issue where a struct literal is being used on an expression
        // where a brace being opened means a block is being started. Look
        // ahead for the next text to see if `span` is followed by a `{`.
391
        let sm = self.r.session.source_map();
392 393 394 395 396
        let mut sp = span;
        loop {
            sp = sm.next_point(sp);
            match sm.span_to_snippet(sp) {
                Ok(ref snippet) => {
M
Mark Rousskov 已提交
397
                    if snippet.chars().any(|c| !c.is_whitespace()) {
398 399 400 401 402 403 404 405 406 407 408
                        break;
                    }
                }
                _ => break,
            }
        }
        let followed_by_brace = match sm.span_to_snippet(sp) {
            Ok(ref snippet) if snippet == "{" => true,
            _ => false,
        };
        // In case this could be a struct literal that needs to be surrounded
409
        // by parentheses, find the appropriate span.
410 411 412 413 414 415 416
        let mut i = 0;
        let mut closing_brace = None;
        loop {
            sp = sm.next_point(sp);
            match sm.span_to_snippet(sp) {
                Ok(ref snippet) => {
                    if snippet == "}" {
417
                        closing_brace = Some(span.to(sp));
418 419 420 421 422 423 424 425 426 427 428 429
                        break;
                    }
                }
                _ => break,
            }
            i += 1;
            // The bigger the span, the more likely we're incorrect --
            // bound it to 100 chars long.
            if i > 100 {
                break;
            }
        }
430
        (followed_by_brace, closing_brace)
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    }

    /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
    /// function.
    /// Returns `true` if able to provide context-dependent help.
    fn smart_resolve_context_dependent_help(
        &mut self,
        err: &mut DiagnosticBuilder<'a>,
        span: Span,
        source: PathSource<'_>,
        res: Res,
        path_str: &str,
        fallback_label: &str,
    ) -> bool {
        let ns = source.namespace();
        let is_expected = &|res| source.is_expected(res);

V
varkor 已提交
448
        let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
            ExprKind::Field(_, ident) => {
                err.span_suggestion(
                    expr.span,
                    "use the path separator to refer to an item",
                    format!("{}::{}", path_str, ident),
                    Applicability::MaybeIncorrect,
                );
                true
            }
            ExprKind::MethodCall(ref segment, ..) => {
                let span = expr.span.with_hi(segment.ident.span.hi());
                err.span_suggestion(
                    span,
                    "use the path separator to refer to an item",
                    format!("{}::{}", path_str, segment.ident),
                    Applicability::MaybeIncorrect,
                );
                true
            }
            _ => false,
        };

471
        let mut bad_struct_syntax_suggestion = |def_id: DefId| {
472 473 474 475 476 477
            let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
            let mut suggested = false;
            match source {
                PathSource::Expr(Some(parent)) => {
                    suggested = path_sep(err, &parent);
                }
478
                PathSource::Expr(None) if followed_by_brace => {
479 480 481 482 483 484 485
                    if let Some(sp) = closing_brace {
                        err.multipart_suggestion(
                            "surround the struct literal with parentheses",
                            vec![
                                (sp.shrink_to_lo(), "(".to_string()),
                                (sp.shrink_to_hi(), ")".to_string()),
                            ],
486 487 488 489
                            Applicability::MaybeIncorrect,
                        );
                    } else {
                        err.span_label(
490 491 492 493 494 495
                            span, // Note the parentheses surrounding the suggestion below
                            format!(
                                "you might want to surround a struct literal with parentheses: \
                                 `({} {{ /* fields */ }})`?",
                                path_str
                            ),
496 497 498
                        );
                    }
                    suggested = true;
M
Mark Rousskov 已提交
499
                }
500 501 502
                _ => {}
            }
            if !suggested {
503 504 505
                if let Some(span) = self.r.definitions.opt_span(def_id) {
                    err.span_label(span, &format!("`{}` defined here", path_str));
                }
M
Mark Rousskov 已提交
506
                err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
507 508 509 510 511
            }
        };

        match (res, source) {
            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
512 513
                err.span_suggestion_verbose(
                    span.shrink_to_hi(),
514
                    "use `!` to invoke the macro",
515
                    "!".to_string(),
516 517 518 519 520 521
                    Applicability::MaybeIncorrect,
                );
                if path_str == "try" && span.rust_2015() {
                    err.note("if you want the `try` keyword, you need to be in the 2018 edition");
                }
            }
522
            (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
523 524
                err.span_label(span, "type aliases cannot be used as traits");
                if nightly_options::is_nightly_build() {
525 526 527 528 529 530 531
                    let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                               `type` alias";
                    if let Some(span) = self.r.definitions.opt_span(def_id) {
                        err.span_help(span, msg);
                    } else {
                        err.help(msg);
                    }
532 533 534 535 536 537 538
                }
            }
            (Res::Def(DefKind::Mod, _), PathSource::Expr(Some(parent))) => {
                if !path_sep(err, &parent) {
                    return false;
                }
            }
539
            (Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct | PathSource::Expr(..)) => {
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
                if let Some(variants) = self.collect_enum_variants(def_id) {
                    if !variants.is_empty() {
                        let msg = if variants.len() == 1 {
                            "try using the enum's variant"
                        } else {
                            "try using one of the enum's variants"
                        };

                        err.span_suggestions(
                            span,
                            msg,
                            variants.iter().map(path_names_to_string),
                            Applicability::MaybeIncorrect,
                        );
                    }
                } else {
                    err.note("did you mean to use one of the enum's variants?");
                }
558
            }
559
            (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
M
Mark Rousskov 已提交
560 561
                if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned()
                {
562
                    let accessible_ctor =
563
                        self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
564 565 566
                    if is_expected(ctor_def) && !accessible_ctor {
                        err.span_label(
                            span,
567
                            "constructor is not visible here due to private fields".to_string(),
568 569 570
                        );
                    }
                } else {
571
                    bad_struct_syntax_suggestion(def_id);
572 573
                }
            }
574 575 576 577 578 579 580
            (
                Res::Def(
                    DefKind::Union | DefKind::Variant | DefKind::Ctor(_, CtorKind::Fictive),
                    def_id,
                ),
                _,
            ) if ns == ValueNS => {
581
                bad_struct_syntax_suggestion(def_id);
582
            }
583 584 585 586
            (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
                if let Some(span) = self.r.definitions.opt_span(def_id) {
                    err.span_label(span, &format!("`{}` defined here", path_str));
                }
M
Mark Rousskov 已提交
587
                err.span_label(span, format!("did you mean `{}( /* fields */ )`?", path_str));
588
            }
589 590 591 592
            (Res::SelfTy(..), _) if ns == ValueNS => {
                err.span_label(span, fallback_label);
                err.note("can't use `Self` as a constructor, you must use the implemented struct");
            }
593
            (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => {
594 595 596 597 598 599 600
                err.note("can't use a type alias as a constructor");
            }
            _ => return false,
        }
        true
    }

M
Mark Rousskov 已提交
601 602 603 604 605 606 607 608
    fn lookup_assoc_candidate<FilterFn>(
        &mut self,
        ident: Ident,
        ns: Namespace,
        filter_fn: FilterFn,
    ) -> Option<AssocSuggestion>
    where
        FilterFn: Fn(Res) -> bool,
609 610
    {
        fn extract_node_id(t: &Ty) -> Option<NodeId> {
V
varkor 已提交
611
            match t.kind {
612 613 614 615 616 617 618 619 620 621 622
                TyKind::Path(None, _) => Some(t.id),
                TyKind::Rptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty),
                // This doesn't handle the remaining `Ty` variants as they are not
                // that commonly the self_type, it might be interesting to provide
                // support for those in future.
                _ => None,
            }
        }

        // Fields are generally expected in the same contexts as locals.
        if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) {
M
Mark Rousskov 已提交
623 624
            if let Some(node_id) =
                self.diagnostic_metadata.current_self_type.as_ref().and_then(extract_node_id)
E
Esteban Küber 已提交
625
            {
626
                // Look for a field with the same name in the current self_type.
627
                if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
628
                    match resolution.base_res() {
629
                        Res::Def(DefKind::Struct | DefKind::Union, did)
M
Mark Rousskov 已提交
630 631
                            if resolution.unresolved_segments() == 0 =>
                        {
632
                            if let Some(field_names) = self.r.field_names.get(&did) {
M
Mark Rousskov 已提交
633 634 635 636
                                if field_names
                                    .iter()
                                    .any(|&field_name| ident.name == field_name.node)
                                {
637 638 639 640 641 642 643 644 645 646
                                    return Some(AssocSuggestion::Field);
                                }
                            }
                        }
                        _ => {}
                    }
                }
            }
        }

E
Esteban Küber 已提交
647
        for assoc_type_ident in &self.diagnostic_metadata.current_trait_assoc_types {
648 649 650 651 652 653 654
            if *assoc_type_ident == ident {
                return Some(AssocSuggestion::AssocItem);
            }
        }

        // Look for associated items in the current trait.
        if let Some((module, _)) = self.current_trait_ref {
655
            if let Ok(binding) = self.r.resolve_ident_in_module(
M
Mark Rousskov 已提交
656 657 658 659 660 661 662
                ModuleOrUniformRoot::Module(module),
                ident,
                ns,
                &self.parent_scope,
                false,
                module.span,
            ) {
663 664
                let res = binding.res();
                if filter_fn(res) {
665
                    return Some(if self.r.has_self.contains(&res.def_id()) {
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
                        AssocSuggestion::MethodWithSelf
                    } else {
                        AssocSuggestion::AssocItem
                    });
                }
            }
        }

        None
    }

    fn lookup_typo_candidate(
        &mut self,
        path: &[Segment],
        ns: Namespace,
        filter_fn: &impl Fn(Res) -> bool,
        span: Span,
    ) -> Option<TypoSuggestion> {
        let mut names = Vec::new();
        if path.len() == 1 {
            // Search in lexical scope.
            // Walk backwards up the ribs in scope and collect candidates.
            for rib in self.ribs[ns].iter().rev() {
                // Locals and type parameters
                for (ident, &res) in &rib.bindings {
                    if filter_fn(res) {
                        names.push(TypoSuggestion::from_res(ident.name, res));
                    }
                }
                // Items in scope
                if let RibKind::ModuleRibKind(module) = rib.kind {
                    // Items from this module
698
                    self.r.add_module_candidates(module, &mut names, &filter_fn);
699 700 701 702 703 704

                    if let ModuleKind::Block(..) = module.kind {
                        // We can see through blocks
                    } else {
                        // Items from the prelude
                        if !module.no_implicit_prelude {
705 706
                            let extern_prelude = self.r.extern_prelude.clone();
                            names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
M
Mark Rousskov 已提交
707 708
                                self.r
                                    .crate_loader
709 710 711 712
                                    .maybe_process_path_extern(ident.name, ident.span)
                                    .and_then(|crate_id| {
                                        let crate_mod = Res::Def(
                                            DefKind::Mod,
M
Mark Rousskov 已提交
713
                                            DefId { krate: crate_id, index: CRATE_DEF_INDEX },
714 715 716 717 718 719 720 721 722 723
                                        );

                                        if filter_fn(crate_mod) {
                                            Some(TypoSuggestion::from_res(ident.name, crate_mod))
                                        } else {
                                            None
                                        }
                                    })
                            }));

724
                            if let Some(prelude) = self.r.prelude {
725
                                self.r.add_module_candidates(prelude, &mut names, &filter_fn);
726 727 728 729 730 731 732 733 734
                            }
                        }
                        break;
                    }
                }
            }
            // Add primitive types to the mix
            if filter_fn(Res::PrimTy(PrimTy::Bool)) {
                names.extend(
735
                    self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
736
                        TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
M
Mark Rousskov 已提交
737
                    }),
738 739 740 741 742
                )
            }
        } else {
            // Search in module.
            let mod_path = &path[..path.len() - 1];
M
Mark Rousskov 已提交
743 744 745
            if let PathResult::Module(module) =
                self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
            {
746
                if let ModuleOrUniformRoot::Module(module) = module {
747
                    self.r.add_module_candidates(module, &mut names, &filter_fn);
748 749 750 751 752 753 754 755 756 757 758 759 760
                }
            }
        }

        let name = path[path.len() - 1].ident.name;
        // Make sure error reporting is deterministic.
        names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());

        match find_best_match_for_name(
            names.iter().map(|suggestion| &suggestion.candidate),
            &name.as_str(),
            None,
        ) {
M
Mark Rousskov 已提交
761 762 763
            Some(found) if found != name => {
                names.into_iter().find(|suggestion| suggestion.candidate == found)
            }
764 765 766 767 768 769
            _ => None,
        }
    }

    /// Only used in a specific case of type ascription suggestions
    fn get_colon_suggestion_span(&self, start: Span) -> Span {
770 771
        let sm = self.r.session.source_map();
        start.to(sm.next_point(start))
772 773
    }

M
Mark Rousskov 已提交
774
    fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) {
775 776
        let sm = self.r.session.source_map();
        let base_snippet = sm.span_to_snippet(base_span);
E
Esteban Küber 已提交
777
        if let Some(sp) = self.diagnostic_metadata.current_type_ascription.last() {
778 779 780
            let mut sp = *sp;
            loop {
                // Try to find the `:`; bail on first non-':' / non-whitespace.
781 782 783 784
                sp = sm.next_point(sp);
                if let Ok(snippet) = sm.span_to_snippet(sp.to(sm.next_point(sp))) {
                    let line_sp = sm.lookup_char_pos(sp.hi()).line;
                    let line_base_sp = sm.lookup_char_pos(base_span.lo()).line;
785 786 787 788 789 790 791 792 793 794 795
                    if snippet == ":" {
                        let mut show_label = true;
                        if line_sp != line_base_sp {
                            err.span_suggestion_short(
                                sp,
                                "did you mean to use `;` here instead?",
                                ";".to_string(),
                                Applicability::MaybeIncorrect,
                            );
                        } else {
                            let colon_sp = self.get_colon_suggestion_span(sp);
M
Mark Rousskov 已提交
796 797
                            let after_colon_sp =
                                self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
798
                            if !sm
M
Mark Rousskov 已提交
799 800
                                .span_to_snippet(after_colon_sp)
                                .map(|s| s == " ")
801 802 803 804 805 806 807 808 809 810 811 812 813 814
                                .unwrap_or(false)
                            {
                                err.span_suggestion(
                                    colon_sp,
                                    "maybe you meant to write a path separator here",
                                    "::".to_string(),
                                    Applicability::MaybeIncorrect,
                                );
                                show_label = false;
                            }
                            if let Ok(base_snippet) = base_snippet {
                                let mut sp = after_colon_sp;
                                for _ in 0..100 {
                                    // Try to find an assignment
815 816
                                    sp = sm.next_point(sp);
                                    let snippet = sm.span_to_snippet(sp.to(sm.next_point(sp)));
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
                                    match snippet {
                                        Ok(ref x) if x.as_str() == "=" => {
                                            err.span_suggestion(
                                                base_span,
                                                "maybe you meant to write an assignment here",
                                                format!("let {}", base_snippet),
                                                Applicability::MaybeIncorrect,
                                            );
                                            show_label = false;
                                            break;
                                        }
                                        Ok(ref x) if x.as_str() == "\n" => break,
                                        Err(_) => break,
                                        Ok(_) => {}
                                    }
                                }
                            }
                        }
                        if show_label {
M
Mark Rousskov 已提交
836 837 838 839
                            err.span_label(
                                base_span,
                                "expecting a type here because of type ascription",
                            );
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
                        }
                        break;
                    } else if !snippet.trim().is_empty() {
                        debug!("tried to find type ascription `:` token, couldn't find it");
                        break;
                    }
                } else {
                    break;
                }
            }
        }
    }

    fn find_module(&mut self, def_id: DefId) -> Option<(Module<'a>, ImportSuggestion)> {
        let mut result = None;
        let mut seen_modules = FxHashSet::default();
856
        let mut worklist = vec![(self.r.graph_root, Vec::new())];
857 858 859

        while let Some((in_module, path_segments)) = worklist.pop() {
            // abort if the module is already found
M
Mark Rousskov 已提交
860 861 862
            if result.is_some() {
                break;
            }
863

A
Aaron Hill 已提交
864
            in_module.for_each_child(self.r, |_, ident, _, name_binding| {
865 866
                // abort if the module is already found or if name_binding is private external
                if result.is_some() || !name_binding.vis.is_visible_locally() {
M
Mark Rousskov 已提交
867
                    return;
868 869 870 871 872 873 874
                }
                if let Some(module) = name_binding.module() {
                    // form the path
                    let mut path_segments = path_segments.clone();
                    path_segments.push(ast::PathSegment::from_ident(ident));
                    let module_def_id = module.def_id().unwrap();
                    if module_def_id == def_id {
M
Mark Rousskov 已提交
875
                        let path = Path { span: name_binding.span, segments: path_segments };
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
                        result = Some((module, ImportSuggestion { did: Some(def_id), path }));
                    } else {
                        // add the module to the lookup
                        if seen_modules.insert(module_def_id) {
                            worklist.push((module, path_segments));
                        }
                    }
                }
            });
        }

        result
    }

    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
        self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
            let mut variants = Vec::new();
A
Aaron Hill 已提交
893
            enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
894 895 896
                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
                    let mut segms = enum_import_suggestion.path.segments.clone();
                    segms.push(ast::PathSegment::from_ident(ident));
M
Mark Rousskov 已提交
897
                    variants.push(Path { span: name_binding.span, segments: segms });
898 899 900 901 902
                }
            });
            variants
        })
    }
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947

    crate fn report_missing_type_error(
        &self,
        path: &[Segment],
    ) -> Option<(Span, &'static str, String, Applicability)> {
        let ident = match path {
            [segment] => segment.ident,
            _ => return None,
        };
        match (
            self.diagnostic_metadata.current_item,
            self.diagnostic_metadata.currently_processing_generics,
        ) {
            (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => {
                // Ignore `fn main()` as we don't want to suggest `fn main<T>()`
            }
            (Some(Item { kind, .. }), true) => {
                // Likely missing type parameter.
                if let Some(generics) = kind.generics() {
                    let msg = "you might be missing a type parameter";
                    let (span, sugg) = if let [.., param] = &generics.params[..] {
                        let span = if let [.., bound] = &param.bounds[..] {
                            bound.span()
                        } else {
                            param.ident.span
                        };
                        (span, format!(", {}", ident))
                    } else {
                        (generics.span, format!("<{}>", ident))
                    };
                    // Do not suggest if this is coming from macro expansion.
                    if !span.from_expansion() {
                        return Some((
                            span.shrink_to_hi(),
                            msg,
                            sugg,
                            Applicability::MaybeIncorrect,
                        ));
                    }
                }
            }
            _ => {}
        }
        None
    }
948
}
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976

impl<'tcx> LifetimeContext<'_, 'tcx> {
    crate fn report_missing_lifetime_specifiers(
        &self,
        span: Span,
        count: usize,
    ) -> DiagnosticBuilder<'tcx> {
        struct_span_err!(
            self.tcx.sess,
            span,
            E0106,
            "missing lifetime specifier{}",
            pluralize!(count)
        )
    }

    crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
        let mut err = struct_span_err!(
            self.tcx.sess,
            lifetime_ref.span,
            E0261,
            "use of undeclared lifetime name `{}`",
            lifetime_ref
        );
        err.span_label(lifetime_ref.span, "undeclared lifetime");
        for missing in &self.missing_named_lifetime_spots {
            match missing {
                MissingLifetimeSpot::Generics(generics) => {
977 978
                    let (span, sugg) = if let Some(param) =
                        generics.params.iter().find(|p| match p.kind {
979 980 981 982 983
                            hir::GenericParamKind::Type {
                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                                ..
                            } => false,
                            _ => true,
984
                        }) {
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
                        (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
                    } else {
                        (generics.span, format!("<{}>", lifetime_ref))
                    };
                    err.span_suggestion(
                        span,
                        &format!("consider introducing lifetime `{}` here", lifetime_ref),
                        sugg,
                        Applicability::MaybeIncorrect,
                    );
                }
                MissingLifetimeSpot::HigherRanked { span, span_type } => {
                    err.span_suggestion(
                        *span,
                        &format!(
                            "consider making the {} lifetime-generic with a new `{}` lifetime",
                            span_type.descr(),
                            lifetime_ref
                        ),
                        span_type.suggestion(&lifetime_ref.to_string()),
                        Applicability::MaybeIncorrect,
                    );
                    err.note(
                        "for more information on higher-ranked polymorphism, visit \
                            https://doc.rust-lang.org/nomicon/hrtb.html",
                    );
                }
            }
        }
        err.emit();
    }

    crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
        if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
            if [
                self.tcx.lang_items().fn_once_trait(),
                self.tcx.lang_items().fn_trait(),
                self.tcx.lang_items().fn_mut_trait(),
            ]
            .contains(&Some(did))
            {
                let (span, span_type) = match &trait_ref.bound_generic_params {
                    [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
                    [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
                };
                self.missing_named_lifetime_spots
                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
                return true;
            }
        };
        false
    }

    crate fn add_missing_lifetime_specifiers_label(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        span: Span,
        count: usize,
        lifetime_names: &FxHashSet<ast::Ident>,
        params: &[ElisionFailureInfo],
    ) {
E
Esteban Küber 已提交
1046 1047
        let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok();

E
Esteban Küber 已提交
1048 1049 1050 1051 1052 1053 1054 1055
        err.span_label(
            span,
            &format!(
                "expected {} lifetime parameter{}",
                if count == 1 { "named".to_string() } else { count.to_string() },
                pluralize!(count)
            ),
        );
1056

E
Esteban Küber 已提交
1057 1058 1059
        let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| {
            err.span_suggestion_verbose(
                span,
E
Esteban Küber 已提交
1060
                &format!("consider using the `{}` lifetime", lifetime_names.iter().next().unwrap()),
E
Esteban Küber 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
                sugg,
                Applicability::MaybeIncorrect,
            );
        };
        let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
            for missing in self.missing_named_lifetime_spots.iter().rev() {
                let mut introduce_suggestion = vec![];
                let msg;
                let should_break;
                introduce_suggestion.push(match missing {
                    MissingLifetimeSpot::Generics(generics) => {
                        msg = "consider introducing a named lifetime parameter".to_string();
                        should_break = true;
                        if let Some(param) = generics.params.iter().find(|p| match p.kind {
                            hir::GenericParamKind::Type {
                                synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                                ..
                            } => false,
                            _ => true,
                        }) {
                            (param.span.shrink_to_lo(), "'a, ".to_string())
                        } else {
                            (generics.span, "<'a>".to_string())
1084 1085
                        }
                    }
E
Esteban Küber 已提交
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
                    MissingLifetimeSpot::HigherRanked { span, span_type } => {
                        msg = format!(
                            "consider making the {} lifetime-generic with a new `'a` lifetime",
                            span_type.descr(),
                        );
                        should_break = false;
                        err.note(
                            "for more information on higher-ranked polymorphism, visit \
                            https://doc.rust-lang.org/nomicon/hrtb.html",
                        );
                        (*span, span_type.suggestion("'a"))
                    }
                });
                for param in params {
                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
                        if snippet.starts_with('&') && !snippet.starts_with("&'") {
                            introduce_suggestion
                                .push((param.span, format!("&'a {}", &snippet[1..])));
                        } else if snippet.starts_with("&'_ ") {
                            introduce_suggestion
                                .push((param.span, format!("&'a {}", &snippet[4..])));
                        }
1108 1109
                    }
                }
E
Esteban Küber 已提交
1110 1111 1112 1113
                introduce_suggestion.push((span, sugg.to_string()));
                err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
                if should_break {
                    break;
1114 1115
                }
            }
E
Esteban Küber 已提交
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
        };

        match (lifetime_names.len(), lifetime_names.iter().next(), snippet.as_deref()) {
            (1, Some(name), Some("&")) => {
                suggest_existing(err, format!("&{} ", name));
            }
            (1, Some(name), Some("'_")) => {
                suggest_existing(err, name.to_string());
            }
            (1, Some(name), Some("")) => {
                suggest_existing(err, format!("{}, ", name).repeat(count));
            }
            (1, Some(name), Some(snippet)) if !snippet.ends_with('>') => {
                suggest_existing(
                    err,
                    format!(
                        "{}<{}>",
                        snippet,
                        std::iter::repeat(name.to_string())
                            .take(count)
                            .collect::<Vec<_>>()
                            .join(", ")
                    ),
                );
            }
            (0, _, Some("&")) if count == 1 => {
                suggest_new(err, "&'a ");
            }
            (0, _, Some("'_")) if count == 1 => {
                suggest_new(err, "'a");
            }
            (0, _, Some(snippet)) if !snippet.ends_with('>') && count == 1 => {
                suggest_new(err, &format!("{}<'a>", snippet));
            }
E
Esteban Küber 已提交
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
            (n, ..) if n > 1 => {
                let spans: Vec<Span> = lifetime_names.iter().map(|lt| lt.span).collect();
                err.span_note(spans, "these named lifetimes are available to use");
                if Some("") == snippet.as_deref() {
                    // This happens when we have `Foo<T>` where we point at the space before `T`,
                    // but this can be confusing so we give a suggestion with placeholders.
                    err.span_suggestion_verbose(
                        span,
                        "consider using one of the available lifetimes here",
                        "'lifetime, ".repeat(count),
                        Applicability::HasPlaceholders,
                    );
                }
            }
E
Esteban Küber 已提交
1164
            _ => {}
1165 1166 1167
        }
    }
}