Merge commit 'd822110d3b5625b9dc80ccc442e06fc3cc851d76' into clippyup

This commit is contained in:
Philipp Krones
2022-12-01 18:29:38 +01:00
parent 58100c014a
commit d05e2865a0
237 changed files with 4245 additions and 1914 deletions

View File

@@ -125,19 +125,19 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
}
}
pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option<ast::Attribute> {
let mut unique_attr = None;
pub fn get_unique_attr<'a>(
sess: &'a Session,
attrs: &'a [ast::Attribute],
name: &'static str,
) -> Option<&'a ast::Attribute> {
let mut unique_attr: Option<&ast::Attribute> = None;
for attr in get_attr(sess, attrs, name) {
match attr.style {
ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
ast::AttrStyle::Inner => {
sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times"))
.span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
.emit();
},
ast::AttrStyle::Outer => {
sess.span_err(attr.span, format!("`{name}` cannot be an outer attribute"));
},
if let Some(duplicate) = unique_attr {
sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times"))
.span_note(duplicate.span, "first definition found here")
.emit();
} else {
unique_attr = Some(attr);
}
}
unique_attr

View File

@@ -91,6 +91,16 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
}
}
fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
if let Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) = res {
cx.typeck_results()
.expr_ty(e)
.has_significant_drop(cx.tcx, cx.param_env)
} else {
false
}
}
#[expect(clippy::too_many_lines)]
fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
struct V<'cx, 'tcx> {
@@ -113,13 +123,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
},
args,
) => match self.cx.qpath_res(path, hir_id) {
Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => {
if self
.cx
.typeck_results()
.expr_ty(e)
.has_significant_drop(self.cx.tcx, self.cx.param_env)
{
res @ (Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_)) => {
if res_has_significant_drop(res, self.cx, e) {
self.eagerness = ForceNoChange;
return;
}
@@ -147,6 +152,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
self.eagerness |= NoChange;
return;
},
ExprKind::Path(ref path) => {
if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) {
self.eagerness = ForceNoChange;
return;
}
},
ExprKind::MethodCall(name, ..) => {
self.eagerness |= self
.cx
@@ -206,7 +217,6 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
| ExprKind::Match(..)
| ExprKind::Closure { .. }
| ExprKind::Field(..)
| ExprKind::Path(_)
| ExprKind::AddrOf(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)

View File

@@ -105,8 +105,6 @@ use rustc_middle::ty::{
layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture,
};
use rustc_middle::ty::{FloatTy, IntTy, UintTy};
use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::SourceMap;
use rustc_span::sym;
@@ -118,36 +116,17 @@ use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
use crate::visitors::for_each_expr;
pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
return Some(version);
} else if let Some(sess) = sess {
if let Some(span) = span {
sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
}
}
None
}
pub fn meets_msrv(msrv: Option<RustcVersion>, lint_msrv: RustcVersion) -> bool {
msrv.map_or(true, |msrv| msrv.meets(lint_msrv))
}
#[macro_export]
macro_rules! extract_msrv_attr {
($context:ident) => {
fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx);
match $crate::get_unique_inner_attr(sess, attrs, "msrv") {
Some(msrv_attr) => {
if let Some(msrv) = msrv_attr.value_str() {
self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
} else {
sess.span_err(msrv_attr.span, "bad clippy attribute");
}
},
_ => (),
}
self.msrv.enter_lint_attrs(sess, attrs);
}
fn exit_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx);
self.msrv.exit_lint_attrs(sess, attrs);
}
};
}

View File

@@ -1,4 +1,11 @@
use std::sync::OnceLock;
use rustc_ast::Attribute;
use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::Span;
use crate::attrs::get_unique_attr;
macro_rules! msrv_aliases {
($($major:literal,$minor:literal,$patch:literal {
@@ -40,3 +47,97 @@ msrv_aliases! {
1,16,0 { STR_REPEAT }
1,55,0 { SEEK_REWIND }
}
fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
return Some(version);
} else if let Some(sess) = sess {
if let Some(span) = span {
sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
}
}
None
}
/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
#[derive(Debug, Clone, Default)]
pub struct Msrv {
stack: Vec<RustcVersion>,
}
impl Msrv {
fn new(initial: Option<RustcVersion>) -> Self {
Self {
stack: Vec::from_iter(initial),
}
}
fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
.and_then(|v| parse_msrv(&v, None, None));
let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
parse_msrv(s, None, None).or_else(|| {
sess.err(format!(
"error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
});
// if both files have an msrv, let's compare them and emit a warning if they differ
if let Some(cargo_msrv) = cargo_msrv
&& let Some(clippy_msrv) = clippy_msrv
&& clippy_msrv != cargo_msrv
{
sess.warn(format!(
"the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
));
}
Self::new(clippy_msrv.or(cargo_msrv))
}
/// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
/// field in `Cargo.toml`
///
/// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
/// `register_{late,early}_pass` callbacks
pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
static PARSED: OnceLock<Msrv> = OnceLock::new();
PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
}
pub fn current(&self) -> Option<RustcVersion> {
self.stack.last().copied()
}
pub fn meets(&self, required: RustcVersion) -> bool {
self.current().map_or(true, |version| version.meets(required))
}
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
if let Some(msrv) = msrv_attr.value_str() {
return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
}
sess.span_err(msrv_attr.span, "bad clippy attribute");
}
None
}
pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if let Some(version) = Self::parse_attr(sess, attrs) {
self.stack.push(version);
}
}
pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if Self::parse_attr(sess, attrs).is_some() {
self.stack.pop();
}
}
}

View File

@@ -60,6 +60,8 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
#[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
#[cfg(feature = "internal")]
pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
@@ -72,7 +74,6 @@ pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekab
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
@@ -101,8 +102,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
#[cfg(feature = "internal")]
pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];

View File

@@ -3,6 +3,7 @@
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
// differ from the time of `rustc` even if the name stays the same.
use crate::msrvs::Msrv;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
@@ -18,20 +19,22 @@ use std::borrow::Cow;
type McfResult = Result<(), (Span, Cow<'static, str>)>;
pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult {
pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
let def_id = body.source.def_id();
let mut current = def_id;
loop {
let predicates = tcx.predicates_of(current);
for (predicate, _) in predicates.predicates {
match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
ty::PredicateKind::Clause(
ty::Clause::RegionOutlives(_)
| ty::Clause::TypeOutlives(_)
| ty::Clause::Projection(_)
| ty::Clause::Trait(..),
)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
@@ -281,7 +284,7 @@ fn check_terminator<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
terminator: &Terminator<'tcx>,
msrv: Option<RustcVersion>,
msrv: &Msrv,
) -> McfResult {
let span = terminator.source_info.span;
match &terminator.kind {
@@ -365,7 +368,7 @@ fn check_terminator<'tcx>(
}
}
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
tcx.is_const_fn(def_id)
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
if let rustc_attr::StabilityLevel::Stable { since, .. } = const_stab.level {
@@ -384,15 +387,12 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bo
let since = rustc_span::Symbol::intern(short_version);
crate::meets_msrv(
msrv,
RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
}),
)
msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
}))
} else {
// Unstable const fn with the feature enabled.
msrv.is_none()
msrv.current().is_none()
}
})
}

View File

@@ -5,6 +5,7 @@
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LintContext};
use rustc_session::Session;
use rustc_span::hygiene;
use rustc_span::source_map::{original_sp, SourceMap};
use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
@@ -204,11 +205,20 @@ pub fn snippet_with_applicability<'a, T: LintContext>(
span: Span,
default: &'a str,
applicability: &mut Applicability,
) -> Cow<'a, str> {
snippet_with_applicability_sess(cx.sess(), span, default, applicability)
}
fn snippet_with_applicability_sess<'a>(
sess: &Session,
span: Span,
default: &'a str,
applicability: &mut Applicability,
) -> Cow<'a, str> {
if *applicability != Applicability::Unspecified && span.from_expansion() {
*applicability = Applicability::MaybeIncorrect;
}
snippet_opt(cx, span).map_or_else(
snippet_opt_sess(sess, span).map_or_else(
|| {
if *applicability == Applicability::MachineApplicable {
*applicability = Applicability::HasPlaceholders;
@@ -226,8 +236,12 @@ pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, defau
}
/// Converts a span to a code snippet. Returns `None` if not available.
pub fn snippet_opt<T: LintContext>(cx: &T, span: Span) -> Option<String> {
cx.sess().source_map().span_to_snippet(span).ok()
pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
snippet_opt_sess(cx.sess(), span)
}
fn snippet_opt_sess(sess: &Session, span: Span) -> Option<String> {
sess.source_map().span_to_snippet(span).ok()
}
/// Converts a span (from a block) to a code snippet if available, otherwise use default.
@@ -277,8 +291,8 @@ pub fn snippet_block<'a, T: LintContext>(
/// Same as `snippet_block`, but adapts the applicability level by the rules of
/// `snippet_with_applicability`.
pub fn snippet_block_with_applicability<'a, T: LintContext>(
cx: &T,
pub fn snippet_block_with_applicability<'a>(
cx: &impl LintContext,
span: Span,
default: &'a str,
indent_relative_to: Option<Span>,
@@ -299,7 +313,17 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
///
/// This will also return whether or not the snippet is a macro call.
pub fn snippet_with_context<'a>(
cx: &LateContext<'_>,
cx: &impl LintContext,
span: Span,
outer: SyntaxContext,
default: &'a str,
applicability: &mut Applicability,
) -> (Cow<'a, str>, bool) {
snippet_with_context_sess(cx.sess(), span, outer, default, applicability)
}
fn snippet_with_context_sess<'a>(
sess: &Session,
span: Span,
outer: SyntaxContext,
default: &'a str,
@@ -318,7 +342,7 @@ pub fn snippet_with_context<'a>(
);
(
snippet_with_applicability(cx, span, default, applicability),
snippet_with_applicability_sess(sess, span, default, applicability),
is_macro_call,
)
}

View File

@@ -176,25 +176,28 @@ impl<'a> Sugg<'a> {
}
/// Prepare a suggestion from an expression.
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
pub fn ast(
cx: &EarlyContext<'_>,
expr: &ast::Expr,
default: &'a str,
ctxt: SyntaxContext,
app: &mut Applicability,
) -> Self {
use rustc_ast::ast::RangeLimits;
let snippet_without_expansion = |cx, span: Span, default| {
if span.from_expansion() {
snippet_with_macro_callsite(cx, span, default)
} else {
snippet(cx, span, default)
}
};
#[expect(clippy::match_wildcard_for_single_variants)]
match expr.kind {
_ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::AddrOf(..)
| ast::ExprKind::Box(..)
| ast::ExprKind::Closure { .. }
| ast::ExprKind::If(..)
| ast::ExprKind::Let(..)
| ast::ExprKind::Unary(..)
| ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)),
| ast::ExprKind::Match(..) => match snippet_with_context(cx, expr.span, ctxt, default, app) {
(snip, false) => Sugg::MaybeParen(snip),
(snip, true) => Sugg::NonParen(snip),
},
ast::ExprKind::Async(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::Break(..)
@@ -224,45 +227,49 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Array(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Await(..)
| ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)),
| ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
AssocOp::DotDot,
lhs.as_ref()
.map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
rhs.as_ref()
.map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
lhs.as_ref().map_or("".into(), |lhs| {
snippet_with_context(cx, lhs.span, ctxt, default, app).0
}),
rhs.as_ref().map_or("".into(), |rhs| {
snippet_with_context(cx, rhs.span, ctxt, default, app).0
}),
),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
AssocOp::DotDotEq,
lhs.as_ref()
.map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
rhs.as_ref()
.map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
lhs.as_ref().map_or("".into(), |lhs| {
snippet_with_context(cx, lhs.span, ctxt, default, app).0
}),
rhs.as_ref().map_or("".into(), |rhs| {
snippet_with_context(cx, rhs.span, ctxt, default, app).0
}),
),
ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
AssocOp::Assign,
snippet_without_expansion(cx, lhs.span, default),
snippet_without_expansion(cx, rhs.span, default),
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
astbinop2assignop(op),
snippet_without_expansion(cx, lhs.span, default),
snippet_without_expansion(cx, rhs.span, default),
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
AssocOp::from_ast_binop(op.node),
snippet_without_expansion(cx, lhs.span, default),
snippet_without_expansion(cx, rhs.span, default),
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
snippet_with_context(cx, rhs.span, ctxt, default, app).0,
),
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::As,
snippet_without_expansion(cx, lhs.span, default),
snippet_without_expansion(cx, ty.span, default),
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
snippet_with_context(cx, ty.span, ctxt, default, app).0,
),
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::Colon,
snippet_without_expansion(cx, lhs.span, default),
snippet_without_expansion(cx, ty.span, default),
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
snippet_with_context(cx, ty.span, ctxt, default, app).0,
),
}
}

View File

@@ -9,7 +9,10 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
use rustc_infer::infer::{TyCtxtInferExt, type_variable::{TypeVariableOrigin, TypeVariableOriginKind}};
use rustc_infer::infer::{
type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
TyCtxtInferExt,
};
use rustc_lint::LateContext;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::ty::{
@@ -189,7 +192,13 @@ pub fn implements_trait<'tcx>(
trait_id: DefId,
ty_params: &[GenericArg<'tcx>],
) -> bool {
implements_trait_with_env(cx.tcx, cx.param_env, ty, trait_id, ty_params.iter().map(|&arg| Some(arg)))
implements_trait_with_env(
cx.tcx,
cx.param_env,
ty,
trait_id,
ty_params.iter().map(|&arg| Some(arg)),
)
}
/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -212,7 +221,11 @@ pub fn implements_trait_with_env<'tcx>(
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
};
let ty_params = tcx.mk_substs(ty_params.into_iter().map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())));
let ty_params = tcx.mk_substs(
ty_params
.into_iter()
.map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
);
infcx
.type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
.must_apply_modulo_regions()
@@ -712,7 +725,9 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
}
inputs = Some(i);
},
PredicateKind::Clause(ty::Clause::Projection(p)) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
PredicateKind::Clause(ty::Clause::Projection(p))
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() =>
{
if output.is_some() {
// Multiple different fn trait impls. Is this even allowed?
return None;
@@ -992,14 +1007,12 @@ pub fn make_projection<'tcx>(
debug_assert!(
generic_count == substs.len(),
"wrong number of substs for `{:?}`: found `{}` expected `{}`.\n\
"wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n\
note: the expected parameters are: {:#?}\n\
the given arguments are: `{:#?}`",
the given arguments are: `{substs:#?}`",
assoc_item.def_id,
substs.len(),
generic_count,
params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
substs,
);
if let Some((idx, (param, arg))) = params
@@ -1017,14 +1030,11 @@ pub fn make_projection<'tcx>(
{
debug_assert!(
false,
"mismatched subst type at index {}: expected a {}, found `{:?}`\n\
"mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
note: the expected parameters are {:#?}\n\
the given arguments are {:#?}",
idx,
the given arguments are {substs:#?}",
param.descr(),
arg,
params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
substs,
params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
);
}
}

View File

@@ -170,22 +170,22 @@ where
cb: F,
}
struct WithStmtGuarg<'a, F> {
struct WithStmtGuard<'a, F> {
val: &'a mut RetFinder<F>,
prev_in_stmt: bool,
}
impl<F> RetFinder<F> {
fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuard<'_, F> {
let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
WithStmtGuarg {
WithStmtGuard {
val: self,
prev_in_stmt,
}
}
}
impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
impl<F> std::ops::Deref for WithStmtGuard<'_, F> {
type Target = RetFinder<F>;
fn deref(&self) -> &Self::Target {
@@ -193,13 +193,13 @@ where
}
}
impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
impl<F> std::ops::DerefMut for WithStmtGuard<'_, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.val
}
}
impl<F> Drop for WithStmtGuarg<'_, F> {
impl<F> Drop for WithStmtGuard<'_, F> {
fn drop(&mut self) {
self.val.in_stmt = self.prev_in_stmt;
}