Auto merge of #106177 - matthiaskrgr:rollup-oe7z8ix, r=matthiaskrgr

Rollup of 4 pull requests

Successful merges:

 - #105515 (Account for macros in const generics)
 - #106146 (Readme: update section on how to run `x.py`)
 - #106150 (Detect when method call on LHS might be shadowed)
 - #106174 (Remove unused empty CSS rules in ayu theme)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-12-27 10:23:32 +00:00
commit a1fc71196a
12 changed files with 306 additions and 27 deletions

View File

@ -20,22 +20,23 @@ Read ["Installation"] from [The Book].
The Rust build system uses a Python script called `x.py` to build the compiler,
which manages the bootstrapping process. It lives at the root of the project.
The `x.py` command can be run directly on most systems in the following format:
The `x.py` command can be run directly on most Unix systems in the following format:
```sh
./x.py <subcommand> [flags]
```
This is how the documentation and examples assume you are running `x.py`.
Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case, you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
This is how the documentation and examples assume you are running `x.py`. Some alternative ways are:
```sh
# Python 3
python3 x.py <subcommand> [flags]
# On a Unix shell if you don't have the necessary `python3` command
./x <subcommand> [flags]
# Python 2.7
python2.7 x.py <subcommand> [flags]
# On the Windows Command Prompt (if .py files are configured to run Python)
x.py <subcommand> [flags]
# You can also run Python yourself, e.g.:
python x.py <subcommand> [flags]
```
More information about `x.py` can be found

View File

@ -1,5 +1,6 @@
use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::MultiSpan;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
@ -30,12 +31,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
_error: Option<TypeError<'tcx>>,
error: Option<TypeError<'tcx>>,
) {
if expr_ty == expected {
return;
}
self.annotate_alternative_method_deref(err, expr, error);
// Use `||` to give these suggestions a precedence
let _ = self.suggest_missing_parentheses(err, expr)
|| self.suggest_remove_last_method_call(err, expr, expected)
@ -316,6 +319,162 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn annotate_alternative_method_deref(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>,
) {
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
let Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Assign(lhs, rhs, _), ..
})) = self.tcx.hir().find(parent) else {return; };
if rhs.hir_id != expr.hir_id || expected.is_closure() {
return;
}
let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; };
let Ok(pick) = self
.probe_for_name(
probe::Mode::MethodCall,
path.ident,
probe::IsSuggestion(true),
self_ty,
deref.hir_id,
probe::ProbeScope::TraitsInScope,
) else {
return;
};
let in_scope_methods = self.probe_for_name_many(
probe::Mode::MethodCall,
path.ident,
probe::IsSuggestion(true),
self_ty,
deref.hir_id,
probe::ProbeScope::TraitsInScope,
);
let other_methods_in_scope: Vec<_> =
in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
let all_methods = self.probe_for_name_many(
probe::Mode::MethodCall,
path.ident,
probe::IsSuggestion(true),
self_ty,
deref.hir_id,
probe::ProbeScope::AllTraits,
);
let suggestions: Vec<_> = all_methods
.into_iter()
.filter(|c| c.item.def_id != pick.item.def_id)
.map(|c| {
let m = c.item;
let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
self.var_for_def(deref.span, param)
});
vec![
(
deref.span.until(base.span),
format!(
"{}({}",
with_no_trimmed_paths!(
self.tcx.def_path_str_with_substs(m.def_id, substs,)
),
match self.tcx.fn_sig(m.def_id).input(0).skip_binder().kind() {
ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
ty::Ref(_, _, _) => "&",
_ => "",
},
),
),
match &args[..] {
[] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
[first, ..] => (base.span.between(first.span), ", ".to_string()),
},
]
})
.collect();
if suggestions.is_empty() {
return;
}
let mut path_span: MultiSpan = path.ident.span.into();
path_span.push_span_label(
path.ident.span,
with_no_trimmed_paths!(format!(
"refers to `{}`",
self.tcx.def_path_str(pick.item.def_id),
)),
);
let container_id = pick.item.container_id(self.tcx);
let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
for def_id in pick.import_ids {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
path_span.push_span_label(
self.tcx.hir().span(hir_id),
format!("`{container}` imported here"),
);
}
let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
[] => return,
[candidate] => format!(
"the method of the same name on {} `{}`",
match candidate.kind {
probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
_ => "trait",
},
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
),
[.., last] if other_methods_in_scope.len() < 5 => {
format!(
"the methods of the same name on {} and `{}`",
other_methods_in_scope[..other_methods_in_scope.len() - 1]
.iter()
.map(|c| format!(
"`{}`",
self.tcx.def_path_str(c.item.container_id(self.tcx))
))
.collect::<Vec<String>>()
.join(", "),
self.tcx.def_path_str(last.item.container_id(self.tcx))
)
}
_ => format!(
"the methods of the same name on {} other traits",
other_methods_in_scope.len()
),
});
err.span_note(
path_span,
&format!(
"the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
path.ident,
),
);
if suggestions.len() > other_methods_in_scope.len() {
err.note(&format!(
"additionally, there are {} other available methods that aren't in scope",
suggestions.len() - other_methods_in_scope.len()
));
}
err.multipart_suggestions(
&format!(
"you might have meant to call {}; you can use the fully-qualified path to call {} \
explicitly",
if suggestions.len() == 1 {
"the other method"
} else {
"one of the other methods"
},
if suggestions.len() == 1 { "it" } else { "one of them" },
),
suggestions,
Applicability::MaybeIncorrect,
);
}
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(

View File

@ -97,7 +97,7 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
}
#[derive(Debug, Clone)]
struct Candidate<'tcx> {
pub(crate) struct Candidate<'tcx> {
// Candidates are (I'm not quite sure, but they are mostly) basically
// some metadata on top of a `ty::AssocItem` (without substs).
//
@ -131,13 +131,13 @@ struct Candidate<'tcx> {
// if `T: Sized`.
xform_self_ty: Ty<'tcx>,
xform_ret_ty: Option<Ty<'tcx>>,
item: ty::AssocItem,
kind: CandidateKind<'tcx>,
import_ids: SmallVec<[LocalDefId; 1]>,
pub(crate) item: ty::AssocItem,
pub(crate) kind: CandidateKind<'tcx>,
pub(crate) import_ids: SmallVec<[LocalDefId; 1]>,
}
#[derive(Debug, Clone)]
enum CandidateKind<'tcx> {
pub(crate) enum CandidateKind<'tcx> {
InherentImplCandidate(
SubstsRef<'tcx>,
// Normalize obligations
@ -322,6 +322,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
#[instrument(level = "debug", skip(self))]
pub(crate) fn probe_for_name_many(
&self,
mode: Mode,
item_name: Ident,
is_suggestion: IsSuggestion,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId,
scope: ProbeScope,
) -> Vec<Candidate<'tcx>> {
self.probe_op(
item_name.span,
mode,
Some(item_name),
None,
is_suggestion,
self_ty,
scope_expr_id,
scope,
|probe_cx| {
Ok(probe_cx
.inherent_candidates
.into_iter()
.chain(probe_cx.extension_candidates)
.collect())
},
)
.unwrap()
}
fn probe_op<OP, R>(
&'a self,
span: Span,

View File

@ -1142,6 +1142,7 @@ impl UnusedDelimLint for UnusedBraces {
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
&& !inner.span.from_expansion()
{
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
}

View File

@ -45,14 +45,6 @@ fi
ci_dir=`cd $(dirname $0) && pwd`
source "$ci_dir/shared.sh"
if command -v python > /dev/null; then
PYTHON="python"
elif command -v python3 > /dev/null; then
PYTHON="python3"
else
PYTHON="python2"
fi
if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
@ -201,7 +193,7 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
mv metrics.json build
fi
CARGO_INCREMENTAL=0 $PYTHON ../x.py check
CARGO_INCREMENTAL=0 ../x check
fi
sccache --show-stats || true

View File

@ -183,11 +183,7 @@ individually rather than as a group) */
/* FIXME: these rules should be at the bottom of the file but currently must be
above the `@media (max-width: 700px)` rules due to a bug in the css checker */
/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
pre.rust .lifetime {}
pre.rust .kw {}
#search-tabs > button:hover, #search-tabs > button.selected {}
pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute {}
pre.rust .kw-2, pre.rust .prelude-ty {}
#settings-menu > a img {
filter: invert(100);

View File

@ -0,0 +1,6 @@
// build-pass
pub fn foo<const BAR: bool> () {}
fn main() {
foo::<{cfg!(feature = "foo")}>();
}

View File

@ -0,0 +1,23 @@
#![allow(unused)]
struct X {
x: (),
}
pub trait A {
fn foo(&mut self, _: usize) -> &mut ();
}
impl A for X {
fn foo(&mut self, _: usize) -> &mut () {
&mut self.x
}
}
impl X {
fn foo(&mut self, _: usize) -> &mut Self {
self
}
}
fn main() {
let mut x = X { x: () };
*x.foo(0) = (); //~ ERROR E0308
}

View File

@ -0,0 +1,25 @@
error[E0308]: mismatched types
--> $DIR/shadowed-lplace-method-2.rs:22:17
|
LL | *x.foo(0) = ();
| --------- ^^ expected struct `X`, found `()`
| |
| expected due to the type of this binding
|
note: the `foo` call is resolved to the method in `X`, shadowing the method of the same name on trait `A`
--> $DIR/shadowed-lplace-method-2.rs:22:8
|
LL | *x.foo(0) = ();
| ^^^ refers to `X::foo`
help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
|
LL | *<_ as A>::foo(&mut x, 0) = ();
| ++++++++++++++++++ ~
help: try wrapping the expression in `X`
|
LL | *x.foo(0) = X { x: () };
| ++++++ +
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,10 @@
// run-rustfix
#![allow(unused_imports)]
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let rc = Rc::new(RefCell::new(true));
*std::cell::RefCell::<_>::borrow_mut(&rc) = false; //~ ERROR E0308
}

View File

@ -0,0 +1,10 @@
// run-rustfix
#![allow(unused_imports)]
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let rc = Rc::new(RefCell::new(true));
*rc.borrow_mut() = false; //~ ERROR E0308
}

View File

@ -0,0 +1,26 @@
error[E0308]: mismatched types
--> $DIR/shadowed-lplace-method.rs:9:24
|
LL | *rc.borrow_mut() = false;
| ---------------- ^^^^^ expected struct `Rc`, found `bool`
| |
| expected due to the type of this binding
|
= note: expected struct `Rc<RefCell<bool>>`
found type `bool`
note: the `borrow_mut` call is resolved to the method in `std::borrow::BorrowMut`, shadowing the method of the same name on the inherent impl for `std::cell::RefCell<T>`
--> $DIR/shadowed-lplace-method.rs:9:9
|
LL | use std::borrow::BorrowMut;
| ---------------------- `std::borrow::BorrowMut` imported here
...
LL | *rc.borrow_mut() = false;
| ^^^^^^^^^^ refers to `std::borrow::BorrowMut::borrow_mut`
help: you might have meant to call the other method; you can use the fully-qualified path to call it explicitly
|
LL | *std::cell::RefCell::<_>::borrow_mut(&rc) = false;
| +++++++++++++++++++++++++++++++++++++ ~
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.