Skip to content

Commit 14b674a

Browse files
author
Alexander Regueiro
committed
Factored out context-dependent help for error reporting.
1 parent 0e2d96e commit 14b674a

File tree

1 file changed

+195
-183
lines changed

1 file changed

+195
-183
lines changed

src/librustc_resolve/lib.rs

Lines changed: 195 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -3124,6 +3124,193 @@ impl<'a> Resolver<'a> {
31243124
)
31253125
}
31263126

3127+
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
3128+
/// function.
3129+
/// Returns `true` if able to provide context-dependent help.
3130+
fn smart_resolve_context_dep_help(
3131+
&mut self,
3132+
err: &mut DiagnosticBuilder<'a>,
3133+
span: Span,
3134+
source: PathSource,
3135+
def: Def,
3136+
path_str: &str,
3137+
fallback_label: &str,
3138+
) -> bool {
3139+
let ns = source.namespace();
3140+
let is_expected = &|def| source.is_expected(def);
3141+
3142+
match (def, source) {
3143+
(Def::Macro(..), _) => {
3144+
err.span_suggestion(
3145+
span,
3146+
"use `!` to invoke the macro",
3147+
format!("{}!", path_str),
3148+
Applicability::MaybeIncorrect,
3149+
);
3150+
}
3151+
(Def::TyAlias(..), PathSource::Trait(_)) => {
3152+
err.span_label(span, "type aliases cannot be used as traits");
3153+
if nightly_options::is_nightly_build() {
3154+
err.note("did you mean to use a trait alias?");
3155+
}
3156+
}
3157+
(Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
3158+
ExprKind::Field(_, ident) => {
3159+
err.span_suggestion(
3160+
parent.span,
3161+
"use the path separator to refer to an item",
3162+
format!("{}::{}", path_str, ident),
3163+
Applicability::MaybeIncorrect,
3164+
);
3165+
}
3166+
ExprKind::MethodCall(ref segment, ..) => {
3167+
let span = parent.span.with_hi(segment.ident.span.hi());
3168+
err.span_suggestion(
3169+
span,
3170+
"use the path separator to refer to an item",
3171+
format!("{}::{}", path_str, segment.ident),
3172+
Applicability::MaybeIncorrect,
3173+
);
3174+
}
3175+
_ => return false,
3176+
},
3177+
(Def::Enum(..), PathSource::TupleStruct)
3178+
| (Def::Enum(..), PathSource::Expr(..)) => {
3179+
if let Some(variants) = self.collect_enum_variants(def) {
3180+
err.note(&format!("did you mean to use one \
3181+
of the following variants?\n{}",
3182+
variants.iter()
3183+
.map(|suggestion| path_names_to_string(suggestion))
3184+
.map(|suggestion| format!("- `{}`", suggestion))
3185+
.collect::<Vec<_>>()
3186+
.join("\n")));
3187+
} else {
3188+
err.note("did you mean to use one of the enum's variants?");
3189+
}
3190+
},
3191+
(Def::Struct(def_id), _) if ns == ValueNS => {
3192+
if let Some((ctor_def, ctor_vis))
3193+
= self.struct_constructors.get(&def_id).cloned() {
3194+
let accessible_ctor = self.is_accessible(ctor_vis);
3195+
if is_expected(ctor_def) && !accessible_ctor {
3196+
err.span_label(span, format!("constructor is not visible \
3197+
here due to private fields"));
3198+
}
3199+
} else {
3200+
// HACK(estebank): find a better way to figure out that this was a
3201+
// parser issue where a struct literal is being used on an expression
3202+
// where a brace being opened means a block is being started. Look
3203+
// ahead for the next text to see if `span` is followed by a `{`.
3204+
let sm = self.session.source_map();
3205+
let mut sp = span;
3206+
loop {
3207+
sp = sm.next_point(sp);
3208+
match sm.span_to_snippet(sp) {
3209+
Ok(ref snippet) => {
3210+
if snippet.chars().any(|c| { !c.is_whitespace() }) {
3211+
break;
3212+
}
3213+
}
3214+
_ => break,
3215+
}
3216+
}
3217+
let followed_by_brace = match sm.span_to_snippet(sp) {
3218+
Ok(ref snippet) if snippet == "{" => true,
3219+
_ => false,
3220+
};
3221+
// In case this could be a struct literal that needs to be surrounded
3222+
// by parenthesis, find the appropriate span.
3223+
let mut i = 0;
3224+
let mut closing_brace = None;
3225+
loop {
3226+
sp = sm.next_point(sp);
3227+
match sm.span_to_snippet(sp) {
3228+
Ok(ref snippet) => {
3229+
if snippet == "}" {
3230+
let sp = span.to(sp);
3231+
if let Ok(snippet) = sm.span_to_snippet(sp) {
3232+
closing_brace = Some((sp, snippet));
3233+
}
3234+
break;
3235+
}
3236+
}
3237+
_ => break,
3238+
}
3239+
i += 1;
3240+
// The bigger the span, the more likely we're incorrect --
3241+
// bound it to 100 chars long.
3242+
if i > 100 {
3243+
break;
3244+
}
3245+
}
3246+
match source {
3247+
PathSource::Expr(Some(parent)) => {
3248+
match parent.node {
3249+
ExprKind::MethodCall(ref path_assignment, _) => {
3250+
err.span_suggestion(
3251+
sm.start_point(parent.span)
3252+
.to(path_assignment.ident.span),
3253+
"use `::` to access an associated function",
3254+
format!("{}::{}",
3255+
path_str,
3256+
path_assignment.ident),
3257+
Applicability::MaybeIncorrect
3258+
);
3259+
},
3260+
_ => {
3261+
err.span_label(
3262+
span,
3263+
format!("did you mean `{} {{ /* fields */ }}`?",
3264+
path_str),
3265+
);
3266+
},
3267+
}
3268+
},
3269+
PathSource::Expr(None) if followed_by_brace == true => {
3270+
if let Some((sp, snippet)) = closing_brace {
3271+
err.span_suggestion(
3272+
sp,
3273+
"surround the struct literal with parenthesis",
3274+
format!("({})", snippet),
3275+
Applicability::MaybeIncorrect,
3276+
);
3277+
} else {
3278+
err.span_label(
3279+
span,
3280+
format!("did you mean `({} {{ /* fields */ }})`?",
3281+
path_str),
3282+
);
3283+
}
3284+
},
3285+
_ => {
3286+
err.span_label(
3287+
span,
3288+
format!("did you mean `{} {{ /* fields */ }}`?",
3289+
path_str),
3290+
);
3291+
},
3292+
}
3293+
}
3294+
}
3295+
(Def::Union(..), _) |
3296+
(Def::Variant(..), _) |
3297+
(Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
3298+
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
3299+
path_str));
3300+
}
3301+
(Def::SelfTy(..), _) if ns == ValueNS => {
3302+
err.span_label(span, fallback_label);
3303+
err.note("can't use `Self` as a constructor, you must use the \
3304+
implemented struct");
3305+
}
3306+
(Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
3307+
err.note("can't use a type alias as a constructor");
3308+
}
3309+
_ => return false,
3310+
}
3311+
true
3312+
}
3313+
31273314
/// Handles error reporting for `smart_resolve_path_fragment` function.
31283315
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
31293316
fn smart_resolve_report_errors(
@@ -3137,7 +3324,7 @@ impl<'a> Resolver<'a> {
31373324
let ns = source.namespace();
31383325
let is_expected = &|def| source.is_expected(def);
31393326
let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
3140-
3327+
31413328
// Make the base error.
31423329
let expected = source.descr_expected();
31433330
let path_str = Segment::names_to_string(path);
@@ -3317,188 +3504,13 @@ impl<'a> Resolver<'a> {
33173504

33183505
// Try context-dependent help if relaxed lookup didn't work.
33193506
if let Some(def) = def {
3320-
match (def, source) {
3321-
(Def::Macro(..), _) => {
3322-
err.span_suggestion(
3323-
span,
3324-
"use `!` to invoke the macro",
3325-
format!("{}!", path_str),
3326-
Applicability::MaybeIncorrect,
3327-
);
3328-
return (err, candidates);
3329-
}
3330-
(Def::TyAlias(..), PathSource::Trait(_)) => {
3331-
err.span_label(span, "type aliases cannot be used as traits");
3332-
if nightly_options::is_nightly_build() {
3333-
err.note("did you mean to use a trait alias?");
3334-
}
3335-
return (err, candidates);
3336-
}
3337-
(Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
3338-
ExprKind::Field(_, ident) => {
3339-
err.span_suggestion(
3340-
parent.span,
3341-
"use the path separator to refer to an item",
3342-
format!("{}::{}", path_str, ident),
3343-
Applicability::MaybeIncorrect,
3344-
);
3345-
return (err, candidates);
3346-
}
3347-
ExprKind::MethodCall(ref segment, ..) => {
3348-
let span = parent.span.with_hi(segment.ident.span.hi());
3349-
err.span_suggestion(
3350-
span,
3351-
"use the path separator to refer to an item",
3352-
format!("{}::{}", path_str, segment.ident),
3353-
Applicability::MaybeIncorrect,
3354-
);
3355-
return (err, candidates);
3356-
}
3357-
_ => {}
3358-
},
3359-
(Def::Enum(..), PathSource::TupleStruct)
3360-
| (Def::Enum(..), PathSource::Expr(..)) => {
3361-
if let Some(variants) = self.collect_enum_variants(def) {
3362-
err.note(&format!("did you mean to use one \
3363-
of the following variants?\n{}",
3364-
variants.iter()
3365-
.map(|suggestion| path_names_to_string(suggestion))
3366-
.map(|suggestion| format!("- `{}`", suggestion))
3367-
.collect::<Vec<_>>()
3368-
.join("\n")));
3369-
3370-
} else {
3371-
err.note("did you mean to use one of the enum's variants?");
3372-
}
3373-
return (err, candidates);
3374-
},
3375-
(Def::Struct(def_id), _) if ns == ValueNS => {
3376-
if let Some((ctor_def, ctor_vis))
3377-
= self.struct_constructors.get(&def_id).cloned() {
3378-
let accessible_ctor = self.is_accessible(ctor_vis);
3379-
if is_expected(ctor_def) && !accessible_ctor {
3380-
err.span_label(span, format!("constructor is not visible \
3381-
here due to private fields"));
3382-
}
3383-
} else {
3384-
// HACK(estebank): find a better way to figure out that this was a
3385-
// parser issue where a struct literal is being used on an expression
3386-
// where a brace being opened means a block is being started. Look
3387-
// ahead for the next text to see if `span` is followed by a `{`.
3388-
let sm = self.session.source_map();
3389-
let mut sp = span;
3390-
loop {
3391-
sp = sm.next_point(sp);
3392-
match sm.span_to_snippet(sp) {
3393-
Ok(ref snippet) => {
3394-
if snippet.chars().any(|c| { !c.is_whitespace() }) {
3395-
break;
3396-
}
3397-
}
3398-
_ => break,
3399-
}
3400-
}
3401-
let followed_by_brace = match sm.span_to_snippet(sp) {
3402-
Ok(ref snippet) if snippet == "{" => true,
3403-
_ => false,
3404-
};
3405-
// In case this could be a struct literal that needs to be surrounded
3406-
// by parenthesis, find the appropriate span.
3407-
let mut i = 0;
3408-
let mut closing_brace = None;
3409-
loop {
3410-
sp = sm.next_point(sp);
3411-
match sm.span_to_snippet(sp) {
3412-
Ok(ref snippet) => {
3413-
if snippet == "}" {
3414-
let sp = span.to(sp);
3415-
if let Ok(snippet) = sm.span_to_snippet(sp) {
3416-
closing_brace = Some((sp, snippet));
3417-
}
3418-
break;
3419-
}
3420-
}
3421-
_ => break,
3422-
}
3423-
i += 1;
3424-
// The bigger the span, the more likely we're
3425-
// incorrect. Bound it to 100 chars long.
3426-
if i > 100 {
3427-
break;
3428-
}
3429-
}
3430-
match source {
3431-
PathSource::Expr(Some(parent)) => {
3432-
match parent.node {
3433-
ExprKind::MethodCall(ref path_assignment, _) => {
3434-
err.span_suggestion(
3435-
sm.start_point(parent.span)
3436-
.to(path_assignment.ident.span),
3437-
"use `::` to access an associated function",
3438-
format!("{}::{}",
3439-
path_str,
3440-
path_assignment.ident),
3441-
Applicability::MaybeIncorrect
3442-
);
3443-
return (err, candidates);
3444-
},
3445-
_ => {
3446-
err.span_label(
3447-
span,
3448-
format!("did you mean `{} {{ /* fields */ }}`?",
3449-
path_str),
3450-
);
3451-
return (err, candidates);
3452-
},
3453-
}
3454-
},
3455-
PathSource::Expr(None) if followed_by_brace == true => {
3456-
if let Some((sp, snippet)) = closing_brace {
3457-
err.span_suggestion(
3458-
sp,
3459-
"surround the struct literal with parenthesis",
3460-
format!("({})", snippet),
3461-
Applicability::MaybeIncorrect,
3462-
);
3463-
} else {
3464-
err.span_label(
3465-
span,
3466-
format!("did you mean `({} {{ /* fields */ }})`?",
3467-
path_str),
3468-
);
3469-
}
3470-
return (err, candidates);
3471-
},
3472-
_ => {
3473-
err.span_label(
3474-
span,
3475-
format!("did you mean `{} {{ /* fields */ }}`?",
3476-
path_str),
3477-
);
3478-
return (err, candidates);
3479-
},
3480-
}
3481-
}
3482-
return (err, candidates);
3483-
}
3484-
(Def::Union(..), _) |
3485-
(Def::Variant(..), _) |
3486-
(Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
3487-
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
3488-
path_str));
3489-
return (err, candidates);
3490-
}
3491-
(Def::SelfTy(..), _) if ns == ValueNS => {
3492-
err.span_label(span, fallback_label);
3493-
err.note("can't use `Self` as a constructor, you must use the \
3494-
implemented struct");
3495-
return (err, candidates);
3496-
}
3497-
(Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
3498-
err.note("can't use a type alias as a constructor");
3499-
return (err, candidates);
3500-
}
3501-
_ => {}
3507+
if self.smart_resolve_context_dep_help(&mut err,
3508+
span,
3509+
source,
3510+
def,
3511+
&path_str,
3512+
&fallback_label) {
3513+
return (err, candidates);
35023514
}
35033515
}
35043516

0 commit comments

Comments
 (0)