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:
bors 2023-10-25 22:17:11 +00:00
commit 7ac9a3a124
59 changed files with 857 additions and 320 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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",

View File

@ -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

View File

@ -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",
}

View File

@ -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,

View File

@ -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)
}
}

View File

@ -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

View File

@ -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...

View File

@ -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(

View File

@ -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()

View File

@ -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

View File

@ -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)),

View File

@ -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>);

View File

@ -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>>;

View File

@ -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(),

View File

@ -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;

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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)
}

View File

@ -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] {""}

View File

@ -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 =

View File

@ -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:#}",
)),
)
}

View File

@ -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",
})
}

View File

@ -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,

View File

@ -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 {

View 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),
}
}
}

View File

@ -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;

View File

@ -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};

View File

@ -50,4 +50,5 @@ TrivialTypeTraversalImpls! {
String,
crate::DebruijnIndex,
crate::AliasRelationDirection,
crate::UniverseIndex,
}

View File

@ -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>,

View File

@ -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>,

View File

@ -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,

View File

@ -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 {

View File

@ -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) {

View File

@ -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);
}

View File

@ -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:

View File

@ -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()

View File

@ -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>) {

View File

@ -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 {

View File

@ -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=()> {

View File

@ -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() {

View File

@ -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);

View File

@ -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() {

View File

@ -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

View File

@ -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
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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`

View File

@ -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

View File

@ -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() {
}

View File

@ -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`.

View File

@ -0,0 +1 @@
pub struct SomeUsefulType;

View File

@ -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() {}

View File

@ -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`.

View File

@ -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`

View File

@ -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`

View File

@ -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`.