Skip to content

Commit 0f0d5d7

Browse files
committedDec 4, 2022
Auto merge of rust-lang#105261 - matthiaskrgr:rollup-9ghhc9c, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#101975 (Suggest to use . instead of :: when accessing a method of an object) - rust-lang#105141 (Fix ICE on invalid variable declarations in macro calls) - rust-lang#105224 (Properly substitute inherent associated types.) - rust-lang#105236 (Add regression test for rust-lang#47814) - rust-lang#105247 (Use parent function WfCheckingContext to check RPITIT.) - rust-lang#105253 (Update a couple of rustbuild deps) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 19c250a + d0335c3 commit 0f0d5d7

33 files changed

+433
-194
lines changed
 

‎compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ pub enum StashKey {
470470
/// Maybe there was a typo where a comma was forgotten before
471471
/// FRU syntax
472472
MaybeFruTypo,
473+
CallAssocMethod,
473474
}
474475

475476
fn default_track_diagnostic(_: &Diagnostic) {}

‎compiler/rustc_hir_analysis/src/astconv/mod.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
347347
assert!(self_ty.is_some());
348348
}
349349
} else {
350-
assert!(self_ty.is_none() && parent_substs.is_empty());
350+
assert!(self_ty.is_none());
351351
}
352352

353353
let arg_count = Self::check_generic_arg_count(
@@ -1821,7 +1821,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18211821

18221822
// Check if we have an enum variant.
18231823
let mut variant_resolution = None;
1824-
if let ty::Adt(adt_def, _) = qself_ty.kind() {
1824+
if let ty::Adt(adt_def, adt_substs) = qself_ty.kind() {
18251825
if adt_def.is_enum() {
18261826
let variant_def = adt_def
18271827
.variants()
@@ -1923,8 +1923,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
19231923
let Some(assoc_ty_did) = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, impl_) else {
19241924
continue;
19251925
};
1926-
// FIXME(inherent_associated_types): This does not substitute parameters.
1927-
let ty = tcx.type_of(assoc_ty_did);
1926+
let item_substs = self.create_substs_for_associated_item(
1927+
span,
1928+
assoc_ty_did,
1929+
assoc_segment,
1930+
adt_substs,
1931+
);
1932+
let ty = tcx.bound_type_of(assoc_ty_did).subst(tcx, item_substs);
19281933
return Ok((ty, DefKind::AssocTy, assoc_ty_did));
19291934
}
19301935
}

‎compiler/rustc_hir_analysis/src/check/wfcheck.rs

+16-17
Original file line numberDiff line numberDiff line change
@@ -1544,7 +1544,7 @@ fn check_fn_or_method<'tcx>(
15441544
check_where_clauses(wfcx, span, def_id);
15451545

15461546
check_return_position_impl_trait_in_trait_bounds(
1547-
tcx,
1547+
wfcx,
15481548
def_id,
15491549
sig.output(),
15501550
hir_decl.output.span(),
@@ -1580,13 +1580,14 @@ fn check_fn_or_method<'tcx>(
15801580

15811581
/// Basically `check_associated_type_bounds`, but separated for now and should be
15821582
/// deduplicated when RPITITs get lowered into real associated items.
1583-
#[tracing::instrument(level = "trace", skip(tcx))]
1583+
#[tracing::instrument(level = "trace", skip(wfcx))]
15841584
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
1585-
tcx: TyCtxt<'tcx>,
1585+
wfcx: &WfCheckingCtxt<'_, 'tcx>,
15861586
fn_def_id: LocalDefId,
15871587
fn_output: Ty<'tcx>,
15881588
span: Span,
15891589
) {
1590+
let tcx = wfcx.tcx();
15901591
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
15911592
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
15921593
{
@@ -1596,22 +1597,20 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
15961597
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
15971598
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
15981599
{
1599-
// Create a new context, since we want the opaque's ParamEnv and not the parent's.
16001600
let span = tcx.def_span(proj.item_def_id);
1601-
enter_wf_checking_ctxt(tcx, span, proj.item_def_id.expect_local(), |wfcx| {
1602-
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
1603-
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
1604-
let normalized_bound = wfcx.normalize(span, None, bound);
1605-
traits::wf::predicate_obligations(
1606-
wfcx.infcx,
1607-
wfcx.param_env,
1608-
wfcx.body_id,
1609-
normalized_bound,
1610-
bound_span,
1611-
)
1612-
});
1613-
wfcx.register_obligations(wf_obligations);
1601+
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
1602+
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
1603+
let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
1604+
let normalized_bound = wfcx.normalize(span, None, bound);
1605+
traits::wf::predicate_obligations(
1606+
wfcx.infcx,
1607+
wfcx.param_env,
1608+
wfcx.body_id,
1609+
normalized_bound,
1610+
bound_span,
1611+
)
16141612
});
1613+
wfcx.register_obligations(wf_obligations);
16151614
}
16161615
}
16171616
}

‎compiler/rustc_hir_typeck/src/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
528528
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
529529
let ty = match res {
530530
Res::Err => {
531+
self.suggest_assoc_method_call(segs);
531532
let e =
532533
self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
533534
self.set_tainted_by_errors(e);

‎compiler/rustc_hir_typeck/src/method/suggest.rs

+61-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::errors;
55
use crate::FnCtxt;
66
use rustc_ast::ast::Mutability;
77
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8+
use rustc_errors::StashKey;
89
use rustc_errors::{
910
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
1011
MultiSpan,
@@ -13,6 +14,8 @@ use rustc_hir as hir;
1314
use rustc_hir::def::DefKind;
1415
use rustc_hir::def_id::DefId;
1516
use rustc_hir::lang_items::LangItem;
17+
use rustc_hir::PatKind::Binding;
18+
use rustc_hir::PathSegment;
1619
use rustc_hir::{ExprKind, Node, QPath};
1720
use rustc_infer::infer::{
1821
type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
@@ -35,11 +38,11 @@ use rustc_trait_selection::traits::{
3538
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
3639
};
3740

38-
use std::cmp::Ordering;
39-
use std::iter;
40-
4141
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
4242
use super::{CandidateSource, MethodError, NoMatchData};
43+
use rustc_hir::intravisit::Visitor;
44+
use std::cmp::Ordering;
45+
use std::iter;
4346

4447
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4548
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -1462,6 +1465,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14621465
false
14631466
}
14641467

1468+
/// For code `rect::area(...)`,
1469+
/// if `rect` is a local variable and `area` is a valid assoc method for it,
1470+
/// we try to suggest `rect.area()`
1471+
pub(crate) fn suggest_assoc_method_call(&self, segs: &[PathSegment<'_>]) {
1472+
debug!("suggest_assoc_method_call segs: {:?}", segs);
1473+
let [seg1, seg2] = segs else { return; };
1474+
let Some(mut diag) =
1475+
self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
1476+
else { return };
1477+
1478+
let map = self.infcx.tcx.hir();
1479+
let body = map.body(rustc_hir::BodyId { hir_id: self.body_id });
1480+
struct LetVisitor<'a> {
1481+
result: Option<&'a hir::Expr<'a>>,
1482+
ident_name: Symbol,
1483+
}
1484+
1485+
impl<'v> Visitor<'v> for LetVisitor<'v> {
1486+
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
1487+
if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind {
1488+
if let Binding(_, _, ident, ..) = pat.kind &&
1489+
ident.name == self.ident_name {
1490+
self.result = *init;
1491+
}
1492+
}
1493+
hir::intravisit::walk_stmt(self, ex);
1494+
}
1495+
}
1496+
1497+
let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
1498+
visitor.visit_body(&body);
1499+
1500+
let parent = self.tcx.hir().get_parent_node(seg1.hir_id);
1501+
if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
1502+
let Some(expr) = visitor.result {
1503+
let self_ty = self.node_ty(expr.hir_id);
1504+
let probe = self.lookup_probe(
1505+
seg2.ident,
1506+
self_ty,
1507+
call_expr,
1508+
ProbeScope::TraitsInScope,
1509+
);
1510+
if probe.is_ok() {
1511+
let sm = self.infcx.tcx.sess.source_map();
1512+
diag.span_suggestion_verbose(
1513+
sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
1514+
"you may have meant to call an instance method",
1515+
".".to_string(),
1516+
Applicability::MaybeIncorrect
1517+
);
1518+
}
1519+
}
1520+
diag.emit();
1521+
}
1522+
14651523
/// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
14661524
fn suggest_calling_method_on_field(
14671525
&self,

‎compiler/rustc_parse/src/parser/stmt.rs

+24-19
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,22 @@ impl<'a> Parser<'a> {
7272

7373
Ok(Some(if self.token.is_keyword(kw::Let) {
7474
self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
75-
} else if self.is_kw_followed_by_ident(kw::Mut) {
76-
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
77-
} else if self.is_kw_followed_by_ident(kw::Auto) {
75+
} else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
76+
self.recover_stmt_local_after_let(lo, attrs, InvalidVariableDeclarationSub::MissingLet)?
77+
} else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() {
7878
self.bump(); // `auto`
79-
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotAuto)?
80-
} else if self.is_kw_followed_by_ident(sym::var) {
79+
self.recover_stmt_local_after_let(
80+
lo,
81+
attrs,
82+
InvalidVariableDeclarationSub::UseLetNotAuto,
83+
)?
84+
} else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() {
8185
self.bump(); // `var`
82-
self.recover_stmt_local(lo, attrs, InvalidVariableDeclarationSub::UseLetNotVar)?
86+
self.recover_stmt_local_after_let(
87+
lo,
88+
attrs,
89+
InvalidVariableDeclarationSub::UseLetNotVar,
90+
)?
8391
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
8492
// We have avoided contextual keywords like `union`, items with `crate` visibility,
8593
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -213,13 +221,21 @@ impl<'a> Parser<'a> {
213221
}
214222
}
215223

216-
fn recover_stmt_local(
224+
fn recover_stmt_local_after_let(
217225
&mut self,
218226
lo: Span,
219227
attrs: AttrWrapper,
220228
subdiagnostic: fn(Span) -> InvalidVariableDeclarationSub,
221229
) -> PResult<'a, Stmt> {
222-
let stmt = self.recover_local_after_let(lo, attrs)?;
230+
let stmt =
231+
self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| {
232+
let local = this.parse_local(attrs)?;
233+
// FIXME - maybe capture semicolon in recovery?
234+
Ok((
235+
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
236+
TrailingToken::None,
237+
))
238+
})?;
223239
self.sess.emit_err(InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
224240
Ok(stmt)
225241
}
@@ -243,17 +259,6 @@ impl<'a> Parser<'a> {
243259
})
244260
}
245261

246-
fn recover_local_after_let(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
247-
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
248-
let local = this.parse_local(attrs)?;
249-
// FIXME - maybe capture semicolon in recovery?
250-
Ok((
251-
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)),
252-
TrailingToken::None,
253-
))
254-
})
255-
}
256-
257262
/// Parses a local variable declaration.
258263
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
259264
let lo = self.prev_token.span;

‎compiler/rustc_resolve/src/diagnostics.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1840,13 +1840,16 @@ impl<'a> Resolver<'a> {
18401840

18411841
(format!("use of undeclared type `{}`", ident), suggestion)
18421842
} else {
1843-
let suggestion = if ident.name == sym::alloc {
1844-
Some((
1843+
let mut suggestion = None;
1844+
if ident.name == sym::alloc {
1845+
suggestion = Some((
18451846
vec![],
18461847
String::from("add `extern crate alloc` to use the `alloc` crate"),
18471848
Applicability::MaybeIncorrect,
18481849
))
1849-
} else {
1850+
}
1851+
1852+
suggestion = suggestion.or_else(|| {
18501853
self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map(
18511854
|sugg| {
18521855
(
@@ -1856,7 +1859,7 @@ impl<'a> Resolver<'a> {
18561859
)
18571860
},
18581861
)
1859-
};
1862+
});
18601863
(format!("use of undeclared crate or module `{}`", ident), suggestion)
18611864
}
18621865
}

‎compiler/rustc_resolve/src/late.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -3365,13 +3365,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
33653365
// Before we start looking for candidates, we have to get our hands
33663366
// on the type user is trying to perform invocation on; basically:
33673367
// we're transforming `HashMap::new` into just `HashMap`.
3368-
let path = match path.split_last() {
3368+
let prefix_path = match path.split_last() {
33693369
Some((_, path)) if !path.is_empty() => path,
33703370
_ => return Some(parent_err),
33713371
};
33723372

33733373
let (mut err, candidates) =
3374-
this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
3374+
this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
33753375

33763376
// There are two different error messages user might receive at
33773377
// this point:
@@ -3415,11 +3415,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
34153415

34163416
if this.should_report_errs() {
34173417
if candidates.is_empty() {
3418-
// When there is no suggested imports, we can just emit the error
3419-
// and suggestions immediately. Note that we bypass the usually error
3420-
// reporting routine (ie via `self.r.report_error`) because we need
3421-
// to post-process the `ResolutionError` above.
3422-
err.emit();
3418+
if path.len() == 2 && prefix_path.len() == 1 {
3419+
// Delay to check whether methond name is an associated function or not
3420+
// ```
3421+
// let foo = Foo {};
3422+
// foo::bar(); // possibly suggest to foo.bar();
3423+
//```
3424+
err.stash(
3425+
prefix_path[0].ident.span,
3426+
rustc_errors::StashKey::CallAssocMethod,
3427+
);
3428+
} else {
3429+
// When there is no suggested imports, we can just emit the error
3430+
// and suggestions immediately. Note that we bypass the usually error
3431+
// reporting routine (ie via `self.r.report_error`) because we need
3432+
// to post-process the `ResolutionError` above.
3433+
err.emit();
3434+
}
34233435
} else {
34243436
// If there are suggested imports, the error reporting is delayed
34253437
this.r.use_injections.push(UseError {
@@ -3428,7 +3440,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
34283440
def_id,
34293441
instead: false,
34303442
suggestion: None,
3431-
path: path.into(),
3443+
path: prefix_path.into(),
34323444
is_call: source.is_call(),
34333445
});
34343446
}

0 commit comments

Comments
 (0)
Please sign in to comment.