mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #117193 - matthiaskrgr:rollup-bygfdcd, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #116401 (Return multiple object-safety violation errors and code improvements to the object-safety check) - #116553 (Do not suggest 'Trait<Assoc=arg>' when in trait impl) - #116931 (Improve the warning messages for the `#[diagnostic::on_unimplemented]`) - #117008 (Uplift `Canonical` to `rustc_type_ir`) - #117009 (On unresolved imports, suggest a disambiguated path if necessary to avoid collision with local items) - #117175 (Rename AsyncCoroutineKind to CoroutineSource) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7ac9a3a124
@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::AsyncCoroutineKind::Block,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_gen_kind: hir::AsyncCoroutineKind,
|
||||
async_gen_kind: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::AsyncCoroutineKind::Closure,
|
||||
hir::CoroutineSource::Closure,
|
||||
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
|
||||
);
|
||||
let hir_id = this.lower_node_id(inner_closure_id);
|
||||
|
@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::AsyncCoroutineKind::Fn,
|
||||
hir::CoroutineSource::Fn,
|
||||
|this| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = this.lower_block_expr(body);
|
||||
|
@ -8,7 +8,7 @@ use rustc_errors::{
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let kind = match use_span.coroutine_kind() {
|
||||
Some(coroutine_kind) => match coroutine_kind {
|
||||
CoroutineKind::Async(async_kind) => match async_kind {
|
||||
AsyncCoroutineKind::Block => "async block",
|
||||
AsyncCoroutineKind::Closure => "async closure",
|
||||
CoroutineSource::Block => "async block",
|
||||
CoroutineSource::Closure => "async closure",
|
||||
_ => bug!("async block/closure expected, but async function found."),
|
||||
},
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
|
@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
};
|
||||
let mir_description = match hir.body(body).coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(gen)) => match gen {
|
||||
hir::AsyncCoroutineKind::Block => " of async block",
|
||||
hir::AsyncCoroutineKind::Closure => " of async closure",
|
||||
hir::AsyncCoroutineKind::Fn => {
|
||||
hir::CoroutineSource::Block => " of async block",
|
||||
hir::CoroutineSource::Closure => " of async closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
|
@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, Mutability};
|
||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &
|
||||
|
||||
fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
|
||||
match coroutine_kind {
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block",
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure",
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn",
|
||||
Some(CoroutineKind::Coroutine) => "coroutine",
|
||||
None => "closure",
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
pub struct Coroutine(pub hir::CoroutineKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
|
||||
if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
|
||||
Status::Unstable(sym::const_async_blocks)
|
||||
} else {
|
||||
Status::Forbidden
|
||||
@ -372,8 +372,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
|
||||
if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
|
||||
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
|
||||
if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
|
||||
ccx.tcx.sess.create_feature_err(
|
||||
errors::UnallowedOpInConstContext { span, msg },
|
||||
sym::const_async_blocks,
|
||||
|
@ -1511,7 +1511,7 @@ impl<'hir> Body<'hir> {
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum CoroutineKind {
|
||||
/// An explicit `async` block or the body of an async function.
|
||||
Async(AsyncCoroutineKind),
|
||||
Async(CoroutineSource),
|
||||
|
||||
/// A coroutine literal created via a `yield` inside a closure.
|
||||
Coroutine,
|
||||
@ -1520,56 +1520,45 @@ pub enum CoroutineKind {
|
||||
impl fmt::Display for CoroutineKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CoroutineKind::Async(k) => fmt::Display::fmt(k, f),
|
||||
CoroutineKind::Async(k) => {
|
||||
if f.alternate() {
|
||||
f.write_str("`async` ")?;
|
||||
} else {
|
||||
f.write_str("async ")?
|
||||
}
|
||||
k.fmt(f)
|
||||
}
|
||||
CoroutineKind::Coroutine => f.write_str("coroutine"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
CoroutineKind::Async(ask) => ask.descr(),
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In the case of a coroutine created as part of an async construct,
|
||||
/// which kind of async construct caused it to be created?
|
||||
/// In the case of a coroutine created as part of an async/gen construct,
|
||||
/// which kind of async/gen construct caused it to be created?
|
||||
///
|
||||
/// This helps error messages but is also used to drive coercions in
|
||||
/// type-checking (see #60424).
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum AsyncCoroutineKind {
|
||||
/// An explicit `async` block written by the user.
|
||||
pub enum CoroutineSource {
|
||||
/// An explicit `async`/`gen` block written by the user.
|
||||
Block,
|
||||
|
||||
/// An explicit `async` closure written by the user.
|
||||
/// An explicit `async`/`gen` closure written by the user.
|
||||
Closure,
|
||||
|
||||
/// The `async` block generated as the body of an async function.
|
||||
/// The `async`/`gen` block generated as the body of an async/gen function.
|
||||
Fn,
|
||||
}
|
||||
|
||||
impl fmt::Display for AsyncCoroutineKind {
|
||||
impl fmt::Display for CoroutineSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
AsyncCoroutineKind::Block => "async block",
|
||||
AsyncCoroutineKind::Closure => "async closure body",
|
||||
AsyncCoroutineKind::Fn => "async fn body",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncCoroutineKind {
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
AsyncCoroutineKind::Block => "`async` block",
|
||||
AsyncCoroutineKind::Closure => "`async` closure body",
|
||||
AsyncCoroutineKind::Fn => "`async fn` body",
|
||||
CoroutineSource::Block => "block",
|
||||
CoroutineSource::Closure => "closure body",
|
||||
CoroutineSource::Fn => "fn body",
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
if self.missing_lifetimes() { "lifetime" } else { "generic" }
|
||||
}
|
||||
|
||||
/// Returns true if the generic type is a trait
|
||||
/// and is being referred to from one of its trait impls
|
||||
fn is_in_trait_impl(&self) -> bool {
|
||||
if self.tcx.is_trait(self.def_id) {
|
||||
// Here we check if the reference to the generic type
|
||||
// is from the 'of_trait' field of the enclosing impl
|
||||
|
||||
let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
|
||||
let parent_item = self
|
||||
.tcx
|
||||
.hir()
|
||||
.get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);
|
||||
|
||||
// Get the HIR id of the trait ref
|
||||
let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Get the HIR id of the 'of_trait' field of the impl
|
||||
let hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) = parent_item
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check that trait is referred to from the of_trait field of impl
|
||||
trait_ref_id == id_in_of_trait
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn num_provided_args(&self) -> usize {
|
||||
if self.missing_lifetimes() {
|
||||
self.num_provided_lifetime_args()
|
||||
@ -955,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
// If there is a single unbound associated type and a single excess generic param
|
||||
// suggest replacing the generic param with the associated type bound
|
||||
if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
|
||||
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
|
||||
let suggestions = iter::zip(unused_generics, &unbound_types)
|
||||
.map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
|
||||
.collect::<Vec<_>>();
|
||||
// Don't suggest if we're in a trait impl as
|
||||
// that would result in invalid syntax (fixes #116464)
|
||||
if !self.is_in_trait_impl() {
|
||||
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
|
||||
let suggestions = iter::zip(unused_generics, &unbound_types)
|
||||
.map(|(potential, name)| {
|
||||
(potential.span().shrink_to_lo(), format!("{name} = "))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !suggestions.is_empty() {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"replace the generic bound{s} with the associated type{s}",
|
||||
s = pluralize!(unbound_types.len())
|
||||
),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if !suggestions.is_empty() {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"replace the generic bound{s} with the associated type{s}",
|
||||
s = pluralize!(unbound_types.len())
|
||||
),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if remove_entire_generics {
|
||||
let span = self
|
||||
|
@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) = (parent_node, callee_node)
|
||||
{
|
||||
let fn_decl_span = if hir.body(body).coroutine_kind
|
||||
== Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure))
|
||||
== Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure))
|
||||
{
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
|
@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// In the case of the async block that we create for a function body,
|
||||
// we expect the return type of the block to match that of the enclosing
|
||||
// function.
|
||||
Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => {
|
||||
Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => {
|
||||
debug!("closure is async fn body");
|
||||
let def_id = self.tcx.hir().body_owner_def_id(body.id());
|
||||
self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
|
||||
|
@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
|
||||
self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
|
||||
use rustc_session::lint;
|
||||
@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) {
|
||||
debug!("fcx {}", self.tag());
|
||||
|
||||
// FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
|
||||
if !canonical_user_type_annotation.is_identity() {
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
|
@ -10,8 +10,8 @@ use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath,
|
||||
Stmt, StmtKind, TyKind, WherePredicate,
|
||||
CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt,
|
||||
StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
@ -536,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Coroutine(def_id, ..)
|
||||
if matches!(
|
||||
self.tcx.coroutine_kind(def_id),
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Closure))
|
||||
Some(CoroutineKind::Async(CoroutineSource::Closure))
|
||||
) =>
|
||||
{
|
||||
errors::SuggestBoxing::AsyncBody
|
||||
|
@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
target: &str,
|
||||
types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
|
||||
) {
|
||||
for (key, values) in types.iter() {
|
||||
for (kind, values) in types.iter() {
|
||||
let count = values.len();
|
||||
let kind = key.descr();
|
||||
for &sp in values {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!(
|
||||
"{}{} {}{}",
|
||||
"{}{} {:#}{}",
|
||||
if count == 1 { "the " } else { "one of the " },
|
||||
target,
|
||||
kind,
|
||||
@ -2952,17 +2951,19 @@ pub enum TyCategory {
|
||||
Foreign,
|
||||
}
|
||||
|
||||
impl TyCategory {
|
||||
fn descr(&self) -> &'static str {
|
||||
impl fmt::Display for TyCategory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Closure => "closure",
|
||||
Self::Opaque => "opaque type",
|
||||
Self::OpaqueFuture => "future",
|
||||
Self::Coroutine(gk) => gk.descr(),
|
||||
Self::Foreign => "foreign type",
|
||||
Self::Closure => "closure".fmt(f),
|
||||
Self::Opaque => "opaque type".fmt(f),
|
||||
Self::OpaqueFuture => "future".fmt(f),
|
||||
Self::Coroutine(gk) => gk.fmt(f),
|
||||
Self::Foreign => "foreign type".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TyCategory {
|
||||
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
|
||||
|
@ -21,35 +21,17 @@
|
||||
//!
|
||||
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::Canonical as IrCanonical;
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::infer::MemberConstraint;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::GenericArg;
|
||||
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
|
||||
use rustc_macros::HashStable;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Index;
|
||||
|
||||
/// A "canonicalized" type `V` is one where all free inference
|
||||
/// variables have been rewritten to "canonical vars". These are
|
||||
/// numbered starting from 0 in order of first appearance.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Canonical<'tcx, V> {
|
||||
pub value: V,
|
||||
pub max_universe: ty::UniverseIndex,
|
||||
pub variables: CanonicalVarInfos<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
|
||||
self.value, self.max_universe, self.variables
|
||||
)
|
||||
}
|
||||
}
|
||||
pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
|
||||
|
||||
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
|
||||
|
||||
@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
|
||||
pub fn is_proven(&self) -> bool {
|
||||
self.value.is_proven()
|
||||
}
|
||||
|
||||
pub fn is_ambiguous(&self) -> bool {
|
||||
!self.is_proven()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, V> Canonical<'tcx, V> {
|
||||
/// Allows you to map the `value` of a canonical while keeping the
|
||||
/// same set of bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the
|
||||
/// name! In particular, the new value `W` must use all **the
|
||||
/// same type/region variables** in **precisely the same order**
|
||||
/// as the original! (The ordering is defined by the
|
||||
/// `TypeFoldable` implementation of the type in question.)
|
||||
///
|
||||
/// An example of a **correct** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'_, T> = ...;
|
||||
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
|
||||
/// ```
|
||||
///
|
||||
/// An example of an **incorrect** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'tcx, T> = ...;
|
||||
/// let ty: Ty<'tcx> = ...;
|
||||
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
|
||||
/// ```
|
||||
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
|
||||
let Canonical { max_universe, variables, value } = self;
|
||||
Canonical { max_universe, variables, value: map_op(value) }
|
||||
}
|
||||
|
||||
/// Allows you to map the `value` of a canonical while keeping the same set of
|
||||
/// bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the name! See
|
||||
/// the comment of [Canonical::unchecked_map] for more details.
|
||||
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
|
||||
let Canonical { max_universe, variables, value: _ } = self;
|
||||
Canonical { max_universe, variables, value }
|
||||
}
|
||||
}
|
||||
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||
|
||||
|
@ -6,7 +6,7 @@ pub mod tls;
|
||||
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::{DepGraph, DepKindStruct};
|
||||
use crate::infer::canonical::CanonicalVarInfo;
|
||||
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::lint::struct_lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
@ -88,6 +88,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
|
||||
type Binder<T> = Binder<'tcx, T>;
|
||||
type TypeAndMut = TypeAndMut<'tcx>;
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
|
||||
type Ty = Ty<'tcx>;
|
||||
type Tys = &'tcx List<Ty<'tcx>>;
|
||||
|
@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> {
|
||||
}
|
||||
ty::Dynamic(..) => "trait object".into(),
|
||||
ty::Closure(..) => "closure".into(),
|
||||
ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
|
||||
ty::Coroutine(def_id, ..) => {
|
||||
format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
|
||||
}
|
||||
ty::CoroutineWitness(..) => "coroutine witness".into(),
|
||||
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
|
||||
ty::Infer(ty::IntVar(_)) => "integer".into(),
|
||||
@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> {
|
||||
ty::FnPtr(_) => "fn pointer".into(),
|
||||
ty::Dynamic(..) => "trait object".into(),
|
||||
ty::Closure(..) => "closure".into(),
|
||||
ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
|
||||
ty::Coroutine(def_id, ..) => {
|
||||
format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
|
||||
}
|
||||
ty::CoroutineWitness(..) => "coroutine witness".into(),
|
||||
ty::Tuple(..) => "tuple".into(),
|
||||
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||
|
@ -106,8 +106,8 @@ pub use self::sty::{
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
|
||||
UserType, UserTypeAnnotationIndex,
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
|
||||
TypeckResults, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
|
||||
pub mod _match;
|
||||
|
@ -449,7 +449,6 @@ TrivialTypeTraversalImpls! {
|
||||
crate::ty::IntVarValue,
|
||||
crate::ty::adjustment::PointerCoercion,
|
||||
crate::ty::RegionVid,
|
||||
crate::ty::UniverseIndex,
|
||||
crate::ty::Variance,
|
||||
::rustc_span::Span,
|
||||
::rustc_span::symbol::Ident,
|
||||
|
@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
|
||||
/// Canonical user type annotation.
|
||||
pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
|
||||
|
||||
impl<'tcx> CanonicalUserType<'tcx> {
|
||||
/// A user-given type annotation attached to a constant. These arise
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
/// given substitutions applied.
|
||||
TypeOf(DefId, UserArgs<'tcx>),
|
||||
}
|
||||
|
||||
pub trait IsIdentity {
|
||||
fn is_identity(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
|
||||
/// i.e., each thing is mapped to a canonical variable with the same index.
|
||||
pub fn is_identity(&self) -> bool {
|
||||
fn is_identity(&self) -> bool {
|
||||
match self.value {
|
||||
UserType::Ty(_) => false,
|
||||
UserType::TypeOf(_, user_args) => {
|
||||
@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A user-given type annotation attached to a constant. These arise
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
/// given substitutions applied.
|
||||
TypeOf(DefId, UserArgs<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> std::fmt::Display for UserType<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||
use thin_vec::ThinVec;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
use crate::errors::{
|
||||
AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
|
||||
@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
namespace: Namespace,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
start_module: Module<'a>,
|
||||
crate_name: Ident,
|
||||
crate_path: ThinVec<ast::PathSegment>,
|
||||
filter_fn: FilterFn,
|
||||
) -> Vec<ImportSuggestion>
|
||||
where
|
||||
@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
Some(x) => Some(x),
|
||||
} {
|
||||
let in_module_is_extern = !in_module.def_id().is_local();
|
||||
// We have to visit module children in deterministic order to avoid
|
||||
// instabilities in reported imports (#43552).
|
||||
in_module.for_each_child(self, |this, ident, ns, name_binding| {
|
||||
// avoid non-importable candidates
|
||||
if !name_binding.is_importable() {
|
||||
@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let res = name_binding.res();
|
||||
if filter_fn(res) {
|
||||
// create the path
|
||||
let mut segms = path_segments.clone();
|
||||
if lookup_ident.span.at_least_rust_2018() {
|
||||
let mut segms = if lookup_ident.span.at_least_rust_2018() {
|
||||
// crate-local absolute paths start with `crate::` in edition 2018
|
||||
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
|
||||
segms.insert(0, ast::PathSegment::from_ident(crate_name));
|
||||
}
|
||||
crate_path.clone()
|
||||
} else {
|
||||
ThinVec::new()
|
||||
};
|
||||
segms.append(&mut path_segments.clone());
|
||||
|
||||
segms.push(ast::PathSegment::from_ident(ident));
|
||||
let path = Path { span: name_binding.span, segments: segms, tokens: None };
|
||||
@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
where
|
||||
FilterFn: Fn(Res) -> bool,
|
||||
{
|
||||
let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
|
||||
let mut suggestions = self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
self.graph_root,
|
||||
Ident::with_dummy_span(kw::Crate),
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
);
|
||||
|
||||
if lookup_ident.span.at_least_rust_2018() {
|
||||
let extern_prelude_names = self.extern_prelude.clone();
|
||||
for (ident, _) in extern_prelude_names.into_iter() {
|
||||
for ident in self.extern_prelude.clone().into_keys() {
|
||||
if ident.span.from_expansion() {
|
||||
// Idents are adjusted to the root context before being
|
||||
// resolved in the extern prelude, so reporting this to the
|
||||
@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
|
||||
if let Some(crate_id) = crate_id {
|
||||
let crate_root = self.expect_module(crate_id.as_def_id());
|
||||
let crate_def_id = crate_id.as_def_id();
|
||||
let crate_root = self.expect_module(crate_def_id);
|
||||
|
||||
// Check if there's already an item in scope with the same name as the crate.
|
||||
// If so, we have to disambiguate the potential import suggestions by making
|
||||
// the paths *global* (i.e., by prefixing them with `::`).
|
||||
let needs_disambiguation =
|
||||
self.resolutions(parent_scope.module).borrow().iter().any(
|
||||
|(key, name_resolution)| {
|
||||
if key.ns == TypeNS
|
||||
&& key.ident == ident
|
||||
&& let Some(binding) = name_resolution.borrow().binding
|
||||
{
|
||||
match binding.res() {
|
||||
// No disambiguation needed if the identically named item we
|
||||
// found in scope actually refers to the crate in question.
|
||||
Res::Def(_, def_id) => def_id != crate_def_id,
|
||||
Res::PrimTy(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut crate_path = ThinVec::new();
|
||||
if needs_disambiguation {
|
||||
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
|
||||
}
|
||||
crate_path.push(ast::PathSegment::from_ident(ident));
|
||||
|
||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
crate_root,
|
||||
ident,
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
));
|
||||
}
|
||||
@ -2554,7 +2584,7 @@ fn show_candidates(
|
||||
|
||||
candidates.iter().for_each(|c| {
|
||||
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
|
||||
.push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
|
||||
.push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
|
||||
});
|
||||
|
||||
// we want consistent results across executions, but candidates are produced
|
||||
|
@ -883,13 +883,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
|
||||
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
|
||||
type T = stable_mir::mir::CoroutineKind;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource};
|
||||
match self {
|
||||
CoroutineKind::Async(async_gen) => {
|
||||
let async_gen = match async_gen {
|
||||
AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block,
|
||||
AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure,
|
||||
AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn,
|
||||
CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
|
||||
CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
|
||||
CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
|
||||
};
|
||||
stable_mir::mir::CoroutineKind::Async(async_gen)
|
||||
}
|
||||
|
@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus
|
||||
.label = invalid on-clause here
|
||||
|
||||
trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute
|
||||
.help = only `message`, `note` and `label` are allowed as options
|
||||
.label = invalid option found here
|
||||
|
||||
trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
|
||||
.help = at least one of the `message`, `note` and `label` options are expected
|
||||
|
||||
trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
|
||||
[none] {""}
|
||||
|
@ -1,5 +1,8 @@
|
||||
use super::{ObligationCauseCode, PredicateObligation};
|
||||
use crate::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_ast::AttrArgs;
|
||||
use rustc_ast::AttrArgsEq;
|
||||
use rustc_ast::AttrKind;
|
||||
use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -342,7 +345,22 @@ pub enum AppendConstMessage {
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_malformed_on_unimplemented_attr)]
|
||||
pub struct NoValueInOnUnimplementedLint;
|
||||
#[help]
|
||||
pub struct MalformedOnUnimplementedAttrLint {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl MalformedOnUnimplementedAttrLint {
|
||||
fn new(span: Span) -> Self {
|
||||
Self { span }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
||||
#[help]
|
||||
pub struct MissingOptionsForOnUnimplementedAttr;
|
||||
|
||||
impl<'tcx> OnUnimplementedDirective {
|
||||
fn parse(
|
||||
@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
|
||||
vec![item.span()],
|
||||
NoValueInOnUnimplementedLint,
|
||||
MalformedOnUnimplementedAttrLint::new(item.span()),
|
||||
);
|
||||
} else {
|
||||
// nothing found
|
||||
@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective {
|
||||
append_const_msg: None,
|
||||
}))
|
||||
} else {
|
||||
let item = attr.get_normal_item();
|
||||
let report_span = match &item.args {
|
||||
AttrArgs::Empty => item.path.span,
|
||||
AttrArgs::Delimited(args) => args.dspan.entire(),
|
||||
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span),
|
||||
AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
|
||||
};
|
||||
|
||||
tcx.emit_spanned_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
|
||||
attr.span,
|
||||
NoValueInOnUnimplementedLint,
|
||||
report_span,
|
||||
MalformedOnUnimplementedAttrLint::new(report_span),
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
} else if is_diagnostic_namespace_variant {
|
||||
tcx.emit_spanned_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
|
||||
attr.span,
|
||||
NoValueInOnUnimplementedLint,
|
||||
);
|
||||
match &attr.kind {
|
||||
AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
|
||||
tcx.emit_spanned_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
|
||||
attr.span,
|
||||
MalformedOnUnimplementedAttrLint::new(attr.span),
|
||||
);
|
||||
}
|
||||
_ => tcx.emit_spanned_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
|
||||
attr.span,
|
||||
MissingOptionsForOnUnimplementedAttr,
|
||||
),
|
||||
};
|
||||
|
||||
Ok(None)
|
||||
} else {
|
||||
let reported =
|
||||
|
@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::is_range_literal;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Node};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, Node};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
@ -2410,7 +2410,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
.and_then(|coroutine_did| {
|
||||
Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
|
||||
CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"),
|
||||
CoroutineKind::Async(AsyncCoroutineKind::Fn) => self
|
||||
CoroutineKind::Async(CoroutineSource::Fn) => self
|
||||
.tcx
|
||||
.parent(coroutine_did)
|
||||
.as_local()
|
||||
@ -2419,10 +2419,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
.map(|name| {
|
||||
format!("future returned by `{name}` is not {trait_name}")
|
||||
})?,
|
||||
CoroutineKind::Async(AsyncCoroutineKind::Block) => {
|
||||
CoroutineKind::Async(CoroutineSource::Block) => {
|
||||
format!("future created by async block is not {trait_name}")
|
||||
}
|
||||
CoroutineKind::Async(AsyncCoroutineKind::Closure) => {
|
||||
CoroutineKind::Async(CoroutineSource::Closure) => {
|
||||
format!("future created by async closure is not {trait_name}")
|
||||
}
|
||||
})
|
||||
@ -2995,11 +2995,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let sp = self.tcx.def_span(def_id);
|
||||
|
||||
// Special-case this to say "async block" instead of `[static coroutine]`.
|
||||
let kind = tcx.coroutine_kind(def_id).unwrap().descr();
|
||||
let kind = tcx.coroutine_kind(def_id).unwrap();
|
||||
err.span_note(
|
||||
sp,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"required because it's used within this {kind}",
|
||||
"required because it's used within this {kind:#}",
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -1611,9 +1611,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> {
|
||||
self.tcx.hir().body(body_id).coroutine_kind.map(|gen_kind| match gen_kind {
|
||||
hir::CoroutineKind::Coroutine => "a coroutine",
|
||||
hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) => "an async block",
|
||||
hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn) => "an async function",
|
||||
hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure) => "an async closure",
|
||||
hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block",
|
||||
hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function",
|
||||
hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure",
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
/// object. Note that object-safe traits can have some
|
||||
/// non-vtable-safe methods, so long as they require `Self: Sized` or
|
||||
/// otherwise ensure that they cannot be used when `Self = Trait`.
|
||||
///
|
||||
/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
|
||||
/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
|
||||
/// [`WHERE_CLAUSES_OBJECT_SAFETY`].
|
||||
pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
|
||||
debug_assert!(tcx.generics_of(trait_def_id).has_self);
|
||||
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
|
||||
@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
|
||||
return false;
|
||||
}
|
||||
|
||||
match virtual_call_violation_for_method(tcx, trait_def_id, method) {
|
||||
None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
|
||||
Some(_) => false,
|
||||
}
|
||||
virtual_call_violations_for_method(tcx, trait_def_id, method)
|
||||
.iter()
|
||||
.all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf))
|
||||
}
|
||||
|
||||
fn object_safety_violations_for_trait(
|
||||
@ -119,7 +122,7 @@ fn object_safety_violations_for_trait(
|
||||
let mut violations: Vec<_> = tcx
|
||||
.associated_items(trait_def_id)
|
||||
.in_definition_order()
|
||||
.filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
|
||||
.flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item))
|
||||
.collect();
|
||||
|
||||
// Check the trait itself.
|
||||
@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
|
||||
/// Returns `Some(_)` if this item makes the containing trait not object safe.
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
fn object_safety_violation_for_assoc_item(
|
||||
fn object_safety_violations_for_assoc_item(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_def_id: DefId,
|
||||
item: ty::AssocItem,
|
||||
) -> Option<ObjectSafetyViolation> {
|
||||
) -> Vec<ObjectSafetyViolation> {
|
||||
// Any item that has a `Self : Sized` requisite is otherwise
|
||||
// exempt from the regulations.
|
||||
if tcx.generics_require_sized_self(item.def_id) {
|
||||
return None;
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
match item.kind {
|
||||
// Associated consts are never object safe, as they can't have `where` bounds yet at all,
|
||||
// and associated const bounds in trait objects aren't a thing yet either.
|
||||
ty::AssocKind::Const => {
|
||||
Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
|
||||
vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)]
|
||||
}
|
||||
ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
|
||||
let node = tcx.hir().get_if_local(item.def_id);
|
||||
// Get an accurate span depending on the violation.
|
||||
let span = match (&v, node) {
|
||||
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
|
||||
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
|
||||
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
|
||||
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
|
||||
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
|
||||
}
|
||||
_ => item.ident(tcx).span,
|
||||
};
|
||||
ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
let node = tcx.hir().get_if_local(item.def_id);
|
||||
// Get an accurate span depending on the violation.
|
||||
let span = match (&v, node) {
|
||||
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
|
||||
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
|
||||
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
|
||||
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
|
||||
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
|
||||
}
|
||||
_ => item.ident(tcx).span,
|
||||
};
|
||||
|
||||
ObjectSafetyViolation::Method(item.name, v, span)
|
||||
}),
|
||||
ObjectSafetyViolation::Method(item.name, v, span)
|
||||
})
|
||||
.collect(),
|
||||
// Associated types can only be object safe if they have `Self: Sized` bounds.
|
||||
ty::AssocKind::Type => {
|
||||
if !tcx.features().generic_associated_types_extended
|
||||
&& !tcx.generics_of(item.def_id).params.is_empty()
|
||||
&& !item.is_impl_trait_in_trait()
|
||||
{
|
||||
Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
|
||||
vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
|
||||
} else {
|
||||
// We will permit associated types if they are explicitly mentioned in the trait object.
|
||||
// We can't check this here, as here we only check if it is guaranteed to not be possible.
|
||||
None
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item(
|
||||
/// object; this does not necessarily imply that the enclosing trait
|
||||
/// is not object safe, because the method might have a where clause
|
||||
/// `Self:Sized`.
|
||||
fn virtual_call_violation_for_method<'tcx>(
|
||||
fn virtual_call_violations_for_method<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
method: ty::AssocItem,
|
||||
) -> Option<MethodViolationCode> {
|
||||
) -> Vec<MethodViolationCode> {
|
||||
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
|
||||
|
||||
// The method's first parameter must be named `self`
|
||||
@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return Some(MethodViolationCode::StaticMethod(sugg));
|
||||
|
||||
// Not having `self` parameter messes up the later checks,
|
||||
// so we need to return instead of pushing
|
||||
return vec![MethodViolationCode::StaticMethod(sugg)];
|
||||
}
|
||||
|
||||
let mut errors = Vec::new();
|
||||
|
||||
for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
|
||||
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
|
||||
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
|
||||
@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return Some(MethodViolationCode::ReferencesSelfInput(span));
|
||||
errors.push(MethodViolationCode::ReferencesSelfInput(span));
|
||||
}
|
||||
}
|
||||
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
|
||||
return Some(MethodViolationCode::ReferencesSelfOutput);
|
||||
errors.push(MethodViolationCode::ReferencesSelfOutput);
|
||||
}
|
||||
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
|
||||
return Some(code);
|
||||
errors.push(code);
|
||||
}
|
||||
|
||||
// We can't monomorphize things like `fn foo<A>(...)`.
|
||||
let own_counts = tcx.generics_of(method.def_id).own_counts();
|
||||
if own_counts.types + own_counts.consts != 0 {
|
||||
return Some(MethodViolationCode::Generic);
|
||||
if own_counts.types > 0 || own_counts.consts > 0 {
|
||||
errors.push(MethodViolationCode::Generic);
|
||||
}
|
||||
|
||||
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
|
||||
@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return Some(MethodViolationCode::UndispatchableReceiver(span));
|
||||
errors.push(MethodViolationCode::UndispatchableReceiver(span));
|
||||
} else {
|
||||
// Do sanity check to make sure the receiver actually has the layout of a pointer.
|
||||
|
||||
@ -593,10 +604,10 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred)
|
||||
}) {
|
||||
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
errors.push(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
}
|
||||
|
||||
None
|
||||
errors
|
||||
}
|
||||
|
||||
/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
|
||||
@ -709,7 +720,6 @@ fn object_ty_for_trait<'tcx>(
|
||||
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
|
||||
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
|
||||
// `self: Wrapper<Self>`.
|
||||
#[allow(dead_code)]
|
||||
fn receiver_is_dispatchable<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
method: ty::AssocItem,
|
||||
|
@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||
_ => unreachable!(),
|
||||
}?;
|
||||
// We don't expect ambiguity.
|
||||
if result.is_ambiguous() {
|
||||
if !result.value.is_proven() {
|
||||
// Rustdoc normalizes possibly not well-formed types, so only
|
||||
// treat this as a bug if we're not in rustdoc.
|
||||
if !tcx.sess.opts.actually_rustdoc {
|
||||
|
169
compiler/rustc_type_ir/src/canonical.rs
Normal file
169
compiler/rustc_type_ir/src/canonical.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use std::fmt;
|
||||
use std::hash;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
|
||||
use crate::fold::{FallibleTypeFolder, TypeFoldable};
|
||||
use crate::visit::{TypeVisitable, TypeVisitor};
|
||||
use crate::TyDecoder;
|
||||
use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex};
|
||||
|
||||
/// A "canonicalized" type `V` is one where all free inference
|
||||
/// variables have been rewritten to "canonical vars". These are
|
||||
/// numbered starting from 0 in order of first appearance.
|
||||
pub struct Canonical<I: Interner, V> {
|
||||
pub value: V,
|
||||
pub max_universe: UniverseIndex,
|
||||
pub variables: I::CanonicalVars,
|
||||
}
|
||||
|
||||
impl<I: Interner, V> Canonical<I, V> {
|
||||
/// Allows you to map the `value` of a canonical while keeping the
|
||||
/// same set of bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the
|
||||
/// name! In particular, the new value `W` must use all **the
|
||||
/// same type/region variables** in **precisely the same order**
|
||||
/// as the original! (The ordering is defined by the
|
||||
/// `TypeFoldable` implementation of the type in question.)
|
||||
///
|
||||
/// An example of a **correct** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<I, T> = ...;
|
||||
/// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, ));
|
||||
/// ```
|
||||
///
|
||||
/// An example of an **incorrect** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<I, T> = ...;
|
||||
/// let ty: Ty<I> = ...;
|
||||
/// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
|
||||
/// ```
|
||||
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
|
||||
let Canonical { max_universe, variables, value } = self;
|
||||
Canonical { max_universe, variables, value: map_op(value) }
|
||||
}
|
||||
|
||||
/// Allows you to map the `value` of a canonical while keeping the same set of
|
||||
/// bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the name! See
|
||||
/// the comment of [Canonical::unchecked_map] for more details.
|
||||
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
|
||||
let Canonical { max_universe, variables, value: _ } = self;
|
||||
Canonical { max_universe, variables, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
self.value.hash(state);
|
||||
self.max_universe.hash(state);
|
||||
self.variables.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V>
|
||||
where
|
||||
I::CanonicalVars: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.value.hash_stable(hcx, hasher);
|
||||
self.max_universe.hash_stable(hcx, hasher);
|
||||
self.variables.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
|
||||
|
||||
impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value == other.value
|
||||
&& self.max_universe == other.max_universe
|
||||
&& self.variables == other.variables
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
|
||||
self.value, self.max_universe, self.variables
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Canonical")
|
||||
.field("value", &self.value)
|
||||
.field("max_universe", &self.max_universe)
|
||||
.field("variables", &self.variables)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: Clone> Clone for Canonical<I, V> {
|
||||
fn clone(&self) -> Self {
|
||||
Canonical {
|
||||
value: self.value.clone(),
|
||||
max_universe: self.max_universe.clone(),
|
||||
variables: self.variables.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
|
||||
|
||||
impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
|
||||
where
|
||||
I::CanonicalVars: TypeFoldable<I>,
|
||||
{
|
||||
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
|
||||
Ok(Canonical {
|
||||
value: self.value.try_fold_with(folder)?,
|
||||
max_universe: self.max_universe.try_fold_with(folder)?,
|
||||
variables: self.variables.try_fold_with(folder)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
|
||||
where
|
||||
I::CanonicalVars: TypeVisitable<I>,
|
||||
{
|
||||
fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> {
|
||||
self.value.visit_with(folder)?;
|
||||
self.max_universe.visit_with(folder)?;
|
||||
self.variables.visit_with(folder)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V>
|
||||
where
|
||||
I::CanonicalVars: Encodable<E>,
|
||||
{
|
||||
fn encode(&self, s: &mut E) {
|
||||
self.value.encode(s);
|
||||
self.max_universe.encode(s);
|
||||
self.variables.encode(s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V>
|
||||
where
|
||||
I::CanonicalVars: Decodable<D>,
|
||||
{
|
||||
fn decode(d: &mut D) -> Self {
|
||||
Canonical {
|
||||
value: Decodable::decode(d),
|
||||
max_universe: Decodable::decode(d),
|
||||
variables: Decodable::decode(d),
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ pub trait Interner: Sized {
|
||||
|
||||
type Binder<T>;
|
||||
type TypeAndMut: Clone + Debug + Hash + Ord;
|
||||
type CanonicalVars: Clone + Debug + Hash + Eq;
|
||||
|
||||
// Kinds of tys
|
||||
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||
|
@ -26,6 +26,7 @@ pub mod visit;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod canonical;
|
||||
mod const_kind;
|
||||
mod debug;
|
||||
mod flags;
|
||||
@ -33,6 +34,7 @@ mod interner;
|
||||
mod predicate_kind;
|
||||
mod region_kind;
|
||||
|
||||
pub use canonical::*;
|
||||
pub use codec::*;
|
||||
pub use const_kind::*;
|
||||
pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
|
||||
|
@ -50,4 +50,5 @@ TrivialTypeTraversalImpls! {
|
||||
String,
|
||||
crate::DebruijnIndex,
|
||||
crate::AliasRelationDirection,
|
||||
crate::UniverseIndex,
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||
}
|
||||
|
||||
// This is manually implemented because a derive would require `I: Encodable`
|
||||
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
|
||||
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for RegionKind<I>
|
||||
where
|
||||
I::EarlyBoundRegion: Encodable<E>,
|
||||
I::BoundRegion: Encodable<E>,
|
||||
|
@ -622,7 +622,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||
}
|
||||
|
||||
// This is manually implemented because a derive would require `I: Encodable`
|
||||
impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
|
||||
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for TyKind<I>
|
||||
where
|
||||
I::ErrorGuaranteed: Encodable<E>,
|
||||
I::AdtDef: Encodable<E>,
|
||||
|
@ -135,12 +135,12 @@ pub enum UnOp {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CoroutineKind {
|
||||
Async(AsyncCoroutineKind),
|
||||
Async(CoroutineSource),
|
||||
Coroutine,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AsyncCoroutineKind {
|
||||
pub enum CoroutineSource {
|
||||
Block,
|
||||
Closure,
|
||||
Fn,
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath};
|
||||
use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -45,7 +45,7 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
|
||||
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
|
||||
use AsyncCoroutineKind::{Block, Closure};
|
||||
use CoroutineSource::{Block, Closure};
|
||||
// For functions, with explicitly defined types, don't warn.
|
||||
// XXXkhuey maybe we should?
|
||||
if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind {
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind};
|
||||
use rustc_hir::{CoroutineSource, Body, CoroutineKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir::CoroutineLayout;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
@ -195,7 +195,7 @@ impl LateLintPass<'_> for AwaitHolding {
|
||||
}
|
||||
|
||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
||||
use AsyncCoroutineKind::{Block, Closure, Fn};
|
||||
use CoroutineSource::{Block, Closure, Fn};
|
||||
if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind {
|
||||
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
|
||||
if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
|
||||
|
@ -4,7 +4,7 @@ use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
|
||||
CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
|
||||
ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
|
||||
..
|
||||
} = block_expr;
|
||||
let closure_body = cx.tcx.hir().body(body);
|
||||
if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block));
|
||||
if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block));
|
||||
then {
|
||||
return Some(closure_body);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
|
||||
}
|
||||
|
||||
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
|
||||
if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind {
|
||||
if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind {
|
||||
if let ExprKind::Block(
|
||||
Block {
|
||||
expr:
|
||||
|
@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
|
||||
use clippy_utils::source::{snippet, walk_span_to_context};
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
|
||||
use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::UpvarCapture;
|
||||
@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
|
||||
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind &&
|
||||
let body = cx.tcx.hir().body(*body) &&
|
||||
matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block)))
|
||||
matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block)))
|
||||
{
|
||||
cx
|
||||
.typeck_results()
|
||||
|
@ -30,7 +30,7 @@ LL | is_send(foo2(Some(true)));
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/async-await-let-else.rs:24:29
|
||||
|
|
||||
LL | async fn bar2<T>(_: T) -> ! {
|
||||
@ -39,7 +39,7 @@ LL | | panic!()
|
||||
LL | | }
|
||||
| |_^
|
||||
= note: required because it captures the following types: `impl Future<Output = !>`
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/async-await-let-else.rs:18:32
|
||||
|
|
||||
LL | async fn foo2(x: Option<bool>) {
|
||||
|
@ -45,7 +45,7 @@ LL | require_send(send_fut);
|
||||
= help: the trait `Sync` is not implemented for `RefCell<i32>`
|
||||
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
|
||||
= note: required for `Arc<RefCell<i32>>` to implement `Send`
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/issue-68112.rs:47:31
|
||||
|
|
||||
LL | async fn ready2<T>(t: T) -> T {
|
||||
|
@ -18,7 +18,7 @@ note: required because it's used within this closure
|
||||
|
|
||||
LL | baz(|| async {
|
||||
| ^^
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/issue-70935-complex-spans.rs:12:67
|
||||
|
|
||||
LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
||||
|
@ -13,7 +13,7 @@ LL | pub async fn run() {
|
||||
|
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
|
||||
= note: required because it captures the following types: `Arc<Mutex<()>>`, `MutexGuard<'_, ()>`, `impl Future<Output = ()>`
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/auxiliary/issue_67893.rs:9:20
|
||||
|
|
||||
LL | pub async fn run() {
|
||||
|
@ -26,7 +26,7 @@ impl Drop for NotSend {
|
||||
impl !Send for NotSend {}
|
||||
|
||||
async fn foo() {
|
||||
//~^ NOTE used within this `async fn` body
|
||||
//~^ NOTE used within this `async` fn body
|
||||
//~| NOTE within this `impl Future
|
||||
let mut x = (NotSend {},);
|
||||
drop(x.0);
|
||||
|
@ -12,7 +12,7 @@ LL | async fn foo() {
|
||||
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
|
||||
= note: required because it appears within the type `(NotSend,)`
|
||||
= note: required because it captures the following types: `(NotSend,)`, `impl Future<Output = ()>`
|
||||
note: required because it's used within this `async fn` body
|
||||
note: required because it's used within this `async` fn body
|
||||
--> $DIR/partial-drop-partial-reinit.rs:28:16
|
||||
|
|
||||
LL | async fn foo() {
|
||||
|
@ -5,12 +5,15 @@ LL | fn use_dyn(v: &dyn Foo) {
|
||||
| ^^^^^^^ `Foo` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/object-safety-err-ret.rs:8:23
|
||||
--> $DIR/object-safety-err-ret.rs:8:8
|
||||
|
|
||||
LL | trait Foo {
|
||||
| --- this trait cannot be made into an object...
|
||||
LL | fn test(&self) -> [u8; bar::<Self>()];
|
||||
| ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
|
||||
| ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type
|
||||
| |
|
||||
| ...because method `test` references the `Self` type in its `where` clause
|
||||
= help: consider moving `test` to another trait
|
||||
= help: consider moving `test` to another trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -23,9 +23,15 @@ trait Boom {}
|
||||
//~^WARN malformed `on_unimplemented` attribute
|
||||
trait Doom {}
|
||||
|
||||
#[diagnostic::on_unimplemented]
|
||||
//~^WARN missing options for `on_unimplemented` attribute
|
||||
//~|WARN missing options for `on_unimplemented` attribute
|
||||
trait Whatever {}
|
||||
|
||||
fn take_foo(_: impl Foo) {}
|
||||
fn take_baz(_: impl Baz) {}
|
||||
fn take_boom(_: impl Boom) {}
|
||||
fn take_whatever(_: impl Whatever) {}
|
||||
|
||||
fn main() {
|
||||
take_foo(1_i32);
|
||||
@ -34,4 +40,6 @@ fn main() {
|
||||
//~^ERROR Boom
|
||||
take_boom(1_i32);
|
||||
//~^ERROR Boom
|
||||
take_whatever(1_i32);
|
||||
//~^ERROR the trait bound `i32: Whatever` is not satisfied
|
||||
}
|
||||
|
@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented = "boom"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
|
||||
warning: missing options for `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: at least one of the `message`, `note` and `label` options are expected
|
||||
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(unsupported = "foo")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: the trait bound `i32: Foo` is not satisfied
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14
|
||||
|
|
||||
LL | take_foo(1_i32);
|
||||
| -------- ^^^^^ the trait `Foo` is not implemented for `i32`
|
||||
@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait Foo {}
|
||||
| ^^^^^^^^^
|
||||
note: required by a bound in `take_foo`
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21
|
||||
|
|
||||
LL | fn take_foo(_: impl Foo) {}
|
||||
| ^^^ required by this bound in `take_foo`
|
||||
@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Boom
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14
|
||||
|
|
||||
LL | take_baz(1_i32);
|
||||
| -------- ^^^^^ the trait `Baz` is not implemented for `i32`
|
||||
@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait Baz {}
|
||||
| ^^^^^^^^^
|
||||
note: required by a bound in `take_baz`
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21
|
||||
|
|
||||
LL | fn take_baz(_: impl Baz) {}
|
||||
| ^^^ required by this bound in `take_baz`
|
||||
@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: Boom
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15
|
||||
|
|
||||
LL | take_boom(1_i32);
|
||||
| --------- ^^^^^ the trait `Boom` is not implemented for `i32`
|
||||
@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one
|
||||
LL | trait Boom {}
|
||||
| ^^^^^^^^^^
|
||||
note: required by a bound in `take_boom`
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22
|
||||
|
|
||||
LL | fn take_boom(_: impl Boom) {}
|
||||
| ^^^^ required by this bound in `take_boom`
|
||||
|
||||
error: aborting due to 3 previous errors; 8 warnings emitted
|
||||
warning: missing options for `on_unimplemented` attribute
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1
|
||||
|
|
||||
LL | #[diagnostic::on_unimplemented]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: at least one of the `message`, `note` and `label` options are expected
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: the trait bound `i32: Whatever` is not satisfied
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19
|
||||
|
|
||||
LL | take_whatever(1_i32);
|
||||
| ------------- ^^^^^ the trait `Whatever` is not implemented for `i32`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1
|
||||
|
|
||||
LL | trait Whatever {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: required by a bound in `take_whatever`
|
||||
--> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26
|
||||
|
|
||||
LL | fn take_whatever(_: impl Whatever) {}
|
||||
| ^^^^^^^^ required by this bound in `take_whatever`
|
||||
|
||||
error: aborting due to 4 previous errors; 10 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
@ -1,22 +1,20 @@
|
||||
#![feature(diagnostic_namespace)]
|
||||
|
||||
#[diagnostic::on_unimplemented(
|
||||
if(Self = "()"),
|
||||
//~^WARN malformed `on_unimplemented` attribute
|
||||
//~|WARN malformed `on_unimplemented` attribute
|
||||
if(Self = ()),
|
||||
message = "not used yet",
|
||||
label = "not used yet",
|
||||
note = "not used yet"
|
||||
message = "custom message",
|
||||
note = "custom note"
|
||||
)]
|
||||
#[diagnostic::on_unimplemented(message = "fallback!!")]
|
||||
#[diagnostic::on_unimplemented(label = "fallback label")]
|
||||
#[diagnostic::on_unimplemented(note = "fallback note")]
|
||||
#[diagnostic::on_unimplemented(message = "fallback2!!")]
|
||||
trait Foo {}
|
||||
|
||||
fn takes_foo(_: impl Foo) {}
|
||||
|
||||
fn main() {
|
||||
takes_foo(());
|
||||
//~^ERROR fallback!!
|
||||
//~^ERROR custom message
|
||||
}
|
||||
|
@ -1,33 +1,23 @@
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
|
||||
|
|
||||
LL | / #[diagnostic::on_unimplemented(
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | if(Self = ()),
|
||||
... |
|
||||
LL | | note = "not used yet"
|
||||
LL | | )]
|
||||
| |__^
|
||||
LL | if(Self = "()"),
|
||||
| ^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
|
||||
|
||||
warning: malformed `on_unimplemented` attribute
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5
|
||||
|
|
||||
LL | / #[diagnostic::on_unimplemented(
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | if(Self = ()),
|
||||
... |
|
||||
LL | | note = "not used yet"
|
||||
LL | | )]
|
||||
| |__^
|
||||
LL | if(Self = "()"),
|
||||
| ^^^^^^^^^^^^^^^ invalid option found here
|
||||
|
|
||||
= help: only `message`, `note` and `label` are allowed as options
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0277]: fallback!!
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
|
||||
error[E0277]: custom message
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15
|
||||
|
|
||||
LL | takes_foo(());
|
||||
| --------- ^^ fallback label
|
||||
@ -35,14 +25,14 @@ LL | takes_foo(());
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Foo` is not implemented for `()`
|
||||
= note: fallback note
|
||||
= note: custom note
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1
|
||||
|
|
||||
LL | trait Foo {}
|
||||
| ^^^^^^^^^
|
||||
note: required by a bound in `takes_foo`
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
|
||||
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22
|
||||
|
|
||||
LL | fn takes_foo(_: impl Foo) {}
|
||||
| ^^^ required by this bound in `takes_foo`
|
||||
|
@ -6,14 +6,14 @@ LL | use empty::issue_56125;
|
||||
|
|
||||
help: consider importing one of these items instead
|
||||
|
|
||||
LL | use ::issue_56125::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use ::issue_56125::last_segment::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use ::issue_56125::non_last_segment::non_last_segment::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use crate::m3::last_segment::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use crate::m3::non_last_segment::non_last_segment::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use issue_56125::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL | use issue_56125::last_segment::issue_56125;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
and 1 other candidate
|
||||
|
||||
error[E0659]: `issue_56125` is ambiguous
|
||||
|
@ -0,0 +1,43 @@
|
||||
// Regression test for #116464
|
||||
// Checks that we do not suggest Trait<..., Assoc=arg> when the trait
|
||||
// is referred to from one of its impls but do so at all other places
|
||||
|
||||
pub trait Trait<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T, S> Trait<T> for i32 {
|
||||
type Assoc = String;
|
||||
}
|
||||
|
||||
// Should not not trigger suggestion here...
|
||||
impl<T, S> Trait<T, S> for () {}
|
||||
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
|
||||
//... but should do so in all of the below cases except the last one
|
||||
fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
|
||||
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
3
|
||||
}
|
||||
|
||||
struct Struct<T: Trait<u32, String>> {
|
||||
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
a: T
|
||||
}
|
||||
|
||||
trait AnotherTrait<T: Trait<T, i32>> {}
|
||||
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
|
||||
impl<T: Trait<u32, String>> Struct<T> {}
|
||||
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
|
||||
// Test for self type. Should not trigger suggestion as it doesn't have an
|
||||
// associated type
|
||||
trait YetAnotherTrait {}
|
||||
impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
|
||||
//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied
|
||||
|
||||
|
||||
fn main() {
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12
|
||||
|
|
||||
LL | impl<T, S> Trait<T, S> for () {}
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12
|
||||
|
|
||||
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
help: replace the generic bound with the associated type
|
||||
|
|
||||
LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> {
|
||||
| +++++++
|
||||
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46
|
||||
|
|
||||
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
help: replace the generic bound with the associated type
|
||||
|
|
||||
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
|
||||
| +++++++
|
||||
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18
|
||||
|
|
||||
LL | struct Struct<T: Trait<u32, String>> {
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
help: replace the generic bound with the associated type
|
||||
|
|
||||
LL | struct Struct<T: Trait<u32, Assoc = String>> {
|
||||
| +++++++
|
||||
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23
|
||||
|
|
||||
LL | trait AnotherTrait<T: Trait<T, i32>> {}
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
help: replace the generic bound with the associated type
|
||||
|
|
||||
LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {}
|
||||
| +++++++
|
||||
|
||||
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9
|
||||
|
|
||||
LL | impl<T: Trait<u32, String>> Struct<T> {}
|
||||
| ^^^^^ expected 1 generic argument
|
||||
|
|
||||
note: trait defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
||||
|
|
||||
LL | pub trait Trait<T> {
|
||||
| ^^^^^ -
|
||||
help: replace the generic bound with the associated type
|
||||
|
|
||||
LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {}
|
||||
| +++++++
|
||||
|
||||
error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58
|
||||
|
|
||||
LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
|
||||
| ^^^^^^ - help: remove this generic argument
|
||||
| |
|
||||
| expected 1 generic argument
|
||||
|
|
||||
note: struct defined here, with 1 generic parameter: `T`
|
||||
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8
|
||||
|
|
||||
LL | struct Struct<T: Trait<u32, String>> {
|
||||
| ^^^^^^ -
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0107`.
|
1
tests/ui/unresolved/auxiliary/library.rs
Normal file
1
tests/ui/unresolved/auxiliary/library.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct SomeUsefulType;
|
@ -0,0 +1,31 @@
|
||||
// Test that we don't prepend `::` to paths referencing crates from the extern prelude
|
||||
// when it can be avoided[^1] since it's more idiomatic to do so.
|
||||
//
|
||||
// [^1]: Counterexample: `unresolved-import-suggest-disambiguated-crate-name.rs`
|
||||
#![feature(decl_macro)] // allows us to create items with hygienic names
|
||||
|
||||
// aux-crate:library=library.rs
|
||||
// edition: 2021
|
||||
|
||||
mod hygiene {
|
||||
make!();
|
||||
macro make() {
|
||||
// This won't conflict with the suggested *non-global* path as the syntax context differs.
|
||||
mod library {}
|
||||
}
|
||||
|
||||
mod module {}
|
||||
use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
|
||||
}
|
||||
|
||||
mod glob {
|
||||
use inner::*;
|
||||
mod inner {
|
||||
mod library {}
|
||||
}
|
||||
|
||||
mod module {}
|
||||
use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,25 @@
|
||||
error[E0432]: unresolved import `module::SomeUsefulType`
|
||||
--> $DIR/unresolved-import-avoid-suggesting-global-path.rs:18:9
|
||||
|
|
||||
LL | use module::SomeUsefulType;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `hygiene::module`
|
||||
|
|
||||
help: consider importing this struct instead
|
||||
|
|
||||
LL | use library::SomeUsefulType;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0432]: unresolved import `module::SomeUsefulType`
|
||||
--> $DIR/unresolved-import-avoid-suggesting-global-path.rs:28:9
|
||||
|
|
||||
LL | use module::SomeUsefulType;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `glob::module`
|
||||
|
|
||||
help: consider importing this struct instead
|
||||
|
|
||||
LL | use library::SomeUsefulType;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
@ -0,0 +1,19 @@
|
||||
// Regression test for issue #116970.
|
||||
//
|
||||
// When we suggest importing an item from a crate found in the extern prelude and there
|
||||
// happens to exist a module or type in the current scope with the same name as the crate,
|
||||
// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
|
||||
//
|
||||
// For context, when it can be avoided we don't prepend `::` to paths referencing crates
|
||||
// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
|
||||
|
||||
// run-rustfix
|
||||
|
||||
// compile-flags: --crate-type=lib
|
||||
// aux-crate:library=library.rs
|
||||
// edition: 2021
|
||||
|
||||
mod library {} // this module shares the same name as the external crate!
|
||||
|
||||
mod module {}
|
||||
pub use ::library::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
|
@ -0,0 +1,19 @@
|
||||
// Regression test for issue #116970.
|
||||
//
|
||||
// When we suggest importing an item from a crate found in the extern prelude and there
|
||||
// happens to exist a module or type in the current scope with the same name as the crate,
|
||||
// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`).
|
||||
//
|
||||
// For context, when it can be avoided we don't prepend `::` to paths referencing crates
|
||||
// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`.
|
||||
|
||||
// run-rustfix
|
||||
|
||||
// compile-flags: --crate-type=lib
|
||||
// aux-crate:library=library.rs
|
||||
// edition: 2021
|
||||
|
||||
mod library {} // this module shares the same name as the external crate!
|
||||
|
||||
mod module {}
|
||||
pub use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType`
|
@ -0,0 +1,14 @@
|
||||
error[E0432]: unresolved import `module::SomeUsefulType`
|
||||
--> $DIR/unresolved-import-suggest-disambiguated-crate-name.rs:19:9
|
||||
|
|
||||
LL | pub use module::SomeUsefulType;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `module`
|
||||
|
|
||||
help: consider importing this struct instead
|
||||
|
|
||||
LL | pub use ::library::SomeUsefulType;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
Loading…
Reference in New Issue
Block a user