extract Rust 2021 prelude logic to its own module
This commit is contained in:
parent
8d42f3da63
commit
17ab9c0ff9
2 changed files with 178 additions and 124 deletions
|
@ -3,6 +3,7 @@
|
||||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
|
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
|
||||||
|
|
||||||
mod confirm;
|
mod confirm;
|
||||||
|
mod prelude2021;
|
||||||
pub mod probe;
|
pub mod probe;
|
||||||
mod suggest;
|
mod suggest;
|
||||||
|
|
||||||
|
@ -10,9 +11,7 @@ pub use self::suggest::{SelfSource, TraitInfo};
|
||||||
pub use self::CandidateSource::*;
|
pub use self::CandidateSource::*;
|
||||||
pub use self::MethodError::*;
|
pub use self::MethodError::*;
|
||||||
|
|
||||||
use crate::check::method::probe::PickKind;
|
|
||||||
use crate::check::FnCtxt;
|
use crate::check::FnCtxt;
|
||||||
use rustc_ast::ast::Mutability;
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -23,9 +22,7 @@ use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
|
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
|
||||||
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::edition::Edition;
|
|
||||||
use rustc_span::symbol::{sym, Ident};
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
|
@ -202,71 +199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let pick =
|
let pick =
|
||||||
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
||||||
|
|
||||||
if span.edition() < Edition::Edition2021 {
|
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick);
|
||||||
if let sym::try_into = segment.ident.name {
|
|
||||||
if !matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
|
|
||||||
self.tcx.struct_span_lint_hir(
|
|
||||||
FUTURE_PRELUDE_COLLISION,
|
|
||||||
call_expr.hir_id,
|
|
||||||
call_expr.span,
|
|
||||||
|lint| {
|
|
||||||
let sp = call_expr.span;
|
|
||||||
let trait_name = self.tcx.def_path_str(pick.item.container.id());
|
|
||||||
|
|
||||||
let mut lint = lint.build(&format!(
|
|
||||||
"trait method `{}` will become ambiguous in Rust 2021",
|
|
||||||
segment.ident.name
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Ok(self_expr) =
|
|
||||||
self.sess().source_map().span_to_snippet(self_expr.span)
|
|
||||||
{
|
|
||||||
let derefs = "*".repeat(pick.autoderefs);
|
|
||||||
|
|
||||||
let autoref = match pick.autoref_or_ptr_adjustment {
|
|
||||||
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
|
||||||
mutbl: Mutability::Mut,
|
|
||||||
..
|
|
||||||
}) => "&mut ",
|
|
||||||
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
|
||||||
mutbl: Mutability::Not,
|
|
||||||
..
|
|
||||||
}) => "&",
|
|
||||||
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
|
|
||||||
};
|
|
||||||
let self_adjusted =
|
|
||||||
if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
|
||||||
pick.autoref_or_ptr_adjustment
|
|
||||||
{
|
|
||||||
format!("{}{} as *const _", derefs, self_expr)
|
|
||||||
} else {
|
|
||||||
format!("{}{}{}", autoref, derefs, self_expr)
|
|
||||||
};
|
|
||||||
lint.span_suggestion(
|
|
||||||
sp,
|
|
||||||
"disambiguate the associated function",
|
|
||||||
format!(
|
|
||||||
"{}::{}({})",
|
|
||||||
trait_name, segment.ident.name, self_adjusted,
|
|
||||||
),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
lint.span_help(
|
|
||||||
sp,
|
|
||||||
&format!(
|
|
||||||
"disambiguate the associated function with `{}::{}(...)`",
|
|
||||||
trait_name, segment.ident,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lint.emit();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for import_id in &pick.import_ids {
|
for import_id in &pick.import_ids {
|
||||||
debug!("used_trait_import: {:?}", import_id);
|
debug!("used_trait_import: {:?}", import_id);
|
||||||
|
@ -551,60 +484,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ProbeScope::TraitsInScope,
|
ProbeScope::TraitsInScope,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if span.edition() < Edition::Edition2021 {
|
self.lint_fully_qualified_call_from_2018(
|
||||||
if let sym::try_into | sym::try_from | sym::from_iter = method_name.name {
|
span,
|
||||||
// No need to warn if either:
|
method_name,
|
||||||
//
|
self_ty,
|
||||||
// * The method comes from std/core, since ten it's the built-in trait.
|
self_ty_span,
|
||||||
// * This is an inherent method called on a specific type, like `Vec::foo(...)`,
|
expr_id,
|
||||||
// since such methods take precedence over trait methods.
|
&pick,
|
||||||
if !matches!(tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core)
|
);
|
||||||
&& !matches!(pick.kind, PickKind::InherentImplPick)
|
|
||||||
{
|
|
||||||
tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
|
|
||||||
// "type" refers to either a type or, more likely, a trait from which
|
|
||||||
// the associated function or method is from.
|
|
||||||
let type_name = tcx.def_path_str(pick.item.container.id());
|
|
||||||
let type_generics = tcx.generics_of(pick.item.container.id());
|
|
||||||
|
|
||||||
let parameter_count =
|
|
||||||
type_generics.count() - (type_generics.has_self as usize);
|
|
||||||
let trait_name = if parameter_count == 0 {
|
|
||||||
type_name
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"{}<{}>",
|
|
||||||
type_name,
|
|
||||||
std::iter::repeat("_")
|
|
||||||
.take(parameter_count)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut lint = lint.build(&format!(
|
|
||||||
"trait-associated function `{}` will become ambiguous in Rust 2021",
|
|
||||||
method_name.name
|
|
||||||
));
|
|
||||||
|
|
||||||
let self_ty = self
|
|
||||||
.sess()
|
|
||||||
.source_map()
|
|
||||||
.span_to_snippet(self_ty_span)
|
|
||||||
.unwrap_or_else(|_| self_ty.to_string());
|
|
||||||
|
|
||||||
lint.span_suggestion(
|
|
||||||
span,
|
|
||||||
"disambiguate the associated function",
|
|
||||||
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
|
|
||||||
lint.emit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("resolve_fully_qualified_call: pick={:?}", pick);
|
debug!("resolve_fully_qualified_call: pick={:?}", pick);
|
||||||
{
|
{
|
||||||
|
|
167
compiler/rustc_typeck/src/check/method/prelude2021.rs
Normal file
167
compiler/rustc_typeck/src/check/method/prelude2021.rs
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
use rustc_ast::Mutability;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_session::lint::builtin::FUTURE_PRELUDE_COLLISION;
|
||||||
|
use rustc_span::symbol::{sym, Ident};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use crate::check::{
|
||||||
|
method::probe::{self, Pick},
|
||||||
|
FnCtxt,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
pub(super) fn lint_dot_call_from_2018(
|
||||||
|
&self,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
segment: &hir::PathSegment<'_>,
|
||||||
|
span: Span,
|
||||||
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
self_expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
pick: &Pick<'tcx>,
|
||||||
|
) {
|
||||||
|
debug!(
|
||||||
|
"lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
|
||||||
|
segment.ident, self_ty, call_expr, self_expr
|
||||||
|
);
|
||||||
|
|
||||||
|
// Rust 2021 and later is already using the new prelude
|
||||||
|
if span.rust_2021() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the method names that were added to prelude in Rust 2021
|
||||||
|
if !matches!(segment.ident.name, sym::try_into) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to lint if method came from std/core, as that will now be in the prelude
|
||||||
|
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tcx.struct_span_lint_hir(
|
||||||
|
FUTURE_PRELUDE_COLLISION,
|
||||||
|
call_expr.hir_id,
|
||||||
|
call_expr.span,
|
||||||
|
|lint| {
|
||||||
|
let sp = call_expr.span;
|
||||||
|
let trait_name = self.tcx.def_path_str(pick.item.container.id());
|
||||||
|
|
||||||
|
let mut lint = lint.build(&format!(
|
||||||
|
"trait method `{}` will become ambiguous in Rust 2021",
|
||||||
|
segment.ident.name
|
||||||
|
));
|
||||||
|
|
||||||
|
if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) {
|
||||||
|
let derefs = "*".repeat(pick.autoderefs);
|
||||||
|
|
||||||
|
let autoref = match pick.autoref_or_ptr_adjustment {
|
||||||
|
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
||||||
|
mutbl: Mutability::Mut,
|
||||||
|
..
|
||||||
|
}) => "&mut ",
|
||||||
|
Some(probe::AutorefOrPtrAdjustment::Autoref {
|
||||||
|
mutbl: Mutability::Not,
|
||||||
|
..
|
||||||
|
}) => "&",
|
||||||
|
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
|
||||||
|
};
|
||||||
|
let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
|
||||||
|
pick.autoref_or_ptr_adjustment
|
||||||
|
{
|
||||||
|
format!("{}{} as *const _", derefs, self_expr)
|
||||||
|
} else {
|
||||||
|
format!("{}{}{}", autoref, derefs, self_expr)
|
||||||
|
};
|
||||||
|
lint.span_suggestion(
|
||||||
|
sp,
|
||||||
|
"disambiguate the associated function",
|
||||||
|
format!("{}::{}({})", trait_name, segment.ident.name, self_adjusted,),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
lint.span_help(
|
||||||
|
sp,
|
||||||
|
&format!(
|
||||||
|
"disambiguate the associated function with `{}::{}(...)`",
|
||||||
|
trait_name, segment.ident,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
lint.emit();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn lint_fully_qualified_call_from_2018(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
method_name: Ident,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
self_ty_span: Span,
|
||||||
|
expr_id: hir::HirId,
|
||||||
|
pick: &Pick<'tcx>,
|
||||||
|
) {
|
||||||
|
// Rust 2021 and later is already using the new prelude
|
||||||
|
if span.rust_2021() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the fully qualified methods added to prelude in Rust 2021
|
||||||
|
if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to lint if method came from std/core, as that will now be in the prelude
|
||||||
|
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
|
||||||
|
// since such methods take precedence over trait methods.
|
||||||
|
if matches!(pick.kind, probe::PickKind::InherentImplPick) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tcx.struct_span_lint_hir(FUTURE_PRELUDE_COLLISION, expr_id, span, |lint| {
|
||||||
|
// "type" refers to either a type or, more likely, a trait from which
|
||||||
|
// the associated function or method is from.
|
||||||
|
let type_name = self.tcx.def_path_str(pick.item.container.id());
|
||||||
|
let type_generics = self.tcx.generics_of(pick.item.container.id());
|
||||||
|
|
||||||
|
let parameter_count = type_generics.count() - (type_generics.has_self as usize);
|
||||||
|
let trait_name = if parameter_count == 0 {
|
||||||
|
type_name
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{}<{}>",
|
||||||
|
type_name,
|
||||||
|
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut lint = lint.build(&format!(
|
||||||
|
"trait-associated function `{}` will become ambiguous in Rust 2021",
|
||||||
|
method_name.name
|
||||||
|
));
|
||||||
|
|
||||||
|
let self_ty = self
|
||||||
|
.sess()
|
||||||
|
.source_map()
|
||||||
|
.span_to_snippet(self_ty_span)
|
||||||
|
.unwrap_or_else(|_| self_ty.to_string());
|
||||||
|
|
||||||
|
lint.span_suggestion(
|
||||||
|
span,
|
||||||
|
"disambiguate the associated function",
|
||||||
|
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
|
||||||
|
lint.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue