summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/def.rs125
-rw-r--r--compiler/rustc_hir/src/hir.rs97
-rw-r--r--compiler/rustc_hir/src/hir_id.rs60
-rw-r--r--compiler/rustc_hir/src/intravisit.rs20
-rw-r--r--compiler/rustc_hir/src/lib.rs3
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs10
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml (renamed from compiler/rustc_typeck/Cargo.toml)3
-rw-r--r--compiler/rustc_hir_analysis/README.md (renamed from compiler/rustc_typeck/README.md)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs (renamed from compiler/rustc_typeck/src/astconv/errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs (renamed from compiler/rustc_typeck/src/astconv/generics.rs)15
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs (renamed from compiler/rustc_typeck/src/astconv/mod.rs)214
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs (renamed from compiler/rustc_typeck/src/bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs (renamed from compiler/rustc_typeck/src/check/check.rs)588
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs (renamed from compiler/rustc_typeck/src/check/compare_method.rs)1099
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs (renamed from compiler/rustc_typeck/src/check/dropck.rs)12
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs (renamed from compiler/rustc_typeck/src/check/intrinsic.rs)32
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs (renamed from compiler/rustc_typeck/src/check/intrinsicck.rs)112
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs (renamed from compiler/rustc_typeck/src/check/mod.rs)504
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs (renamed from compiler/rustc_typeck/src/check/region.rs)8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs (renamed from compiler/rustc_typeck/src/check/wfcheck.rs)195
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs (renamed from compiler/rustc_typeck/src/check_unused.rs)31
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs572
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls.rs)18
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs (renamed from compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs)58
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs (renamed from compiler/rustc_typeck/src/coherence/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs (renamed from compiler/rustc_typeck/src/coherence/orphan.rs)38
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs (renamed from compiler/rustc_typeck/src/coherence/unsafety.rs)32
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs (renamed from compiler/rustc_typeck/src/collect.rs)1302
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs481
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs (renamed from compiler/rustc_typeck/src/collect/item_bounds.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs (renamed from compiler/rustc_resolve/src/late/lifetimes.rs)139
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs707
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs (renamed from compiler/rustc_typeck/src/collect/type_of.rs)128
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs (renamed from compiler/rustc_typeck/src/constrained_generic_params.rs)10
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs (renamed from compiler/rustc_typeck/src/errors.rs)233
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs (renamed from compiler/rustc_typeck/src/hir_wf_check.rs)58
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs (renamed from compiler/rustc_typeck/src/impl_wf_check.rs)43
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs (renamed from compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs)98
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs (renamed from compiler/rustc_typeck/src/lib.rs)81
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs (renamed from compiler/rustc_typeck/src/outlives/explicit.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs (renamed from compiler/rustc_typeck/src/outlives/implicit_infer.rs)4
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs (renamed from compiler/rustc_typeck/src/outlives/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/test.rs (renamed from compiler/rustc_typeck/src/outlives/test.rs)6
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs (renamed from compiler/rustc_typeck/src/outlives/utils.rs)17
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors.rs (renamed from compiler/rustc_typeck/src/structured_errors.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs (renamed from compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs (renamed from compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs (renamed from compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs (renamed from compiler/rustc_typeck/src/variance/constraints.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs (renamed from compiler/rustc_typeck/src/variance/mod.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/solve.rs (renamed from compiler/rustc_typeck/src/variance/solve.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs (renamed from compiler/rustc_typeck/src/variance/terms.rs)0
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs (renamed from compiler/rustc_typeck/src/variance/test.rs)7
-rw-r--r--compiler/rustc_hir_analysis/src/variance/xform.rs (renamed from compiler/rustc_typeck/src/variance/xform.rs)0
-rw-r--r--compiler/rustc_hir_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs8
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml28
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs (renamed from compiler/rustc_typeck/src/check/_match.rs)19
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs (renamed from compiler/rustc_typeck/src/check/autoderef.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs (renamed from compiler/rustc_typeck/src/check/callee.rs)401
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs (renamed from compiler/rustc_typeck/src/check/cast.rs)174
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs324
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs (renamed from compiler/rustc_typeck/src/check/closure.rs)37
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs (renamed from compiler/rustc_typeck/src/check/coercion.rs)83
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs (renamed from compiler/rustc_typeck/src/check/demand.rs)135
-rw-r--r--compiler/rustc_hir_typeck/src/diverges.rs (renamed from compiler/rustc_typeck/src/check/diverges.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs126
-rw-r--r--compiler/rustc_hir_typeck/src/expectation.rs (renamed from compiler/rustc_typeck/src/check/expectation.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs (renamed from compiler/rustc_typeck/src/check/expr.rs)118
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs (renamed from compiler/rustc_typeck/src/expr_use_visitor.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs (renamed from compiler/rustc_typeck/src/check/fallback.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs)116
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/checks.rs)72
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/mod.rs)26
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs (renamed from compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs)199
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs (renamed from compiler/rustc_typeck/src/check/gather_locals.rs)3
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs)2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs (renamed from compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs (renamed from compiler/rustc_typeck/src/check/generator_interior.rs)49
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs (renamed from compiler/rustc_typeck/src/check/inherited.rs)38
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs108
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs507
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs (renamed from compiler/rustc_typeck/src/mem_categorization.rs)24
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs (renamed from compiler/rustc_typeck/src/check/method/confirm.rs)6
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs (renamed from compiler/rustc_typeck/src/check/method/mod.rs)5
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs (renamed from compiler/rustc_typeck/src/check/method/prelude2021.rs)121
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs (renamed from compiler/rustc_typeck/src/check/method/probe.rs)163
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs (renamed from compiler/rustc_typeck/src/check/method/suggest.rs)388
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs (renamed from compiler/rustc_typeck/src/check/op.rs)15
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs (renamed from compiler/rustc_typeck/src/check/pat.rs)10
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs (renamed from compiler/rustc_typeck/src/check/place_op.rs)4
-rw-r--r--compiler/rustc_hir_typeck/src/rvalue_scopes.rs (renamed from compiler/rustc_typeck/src/check/rvalue_scopes.rs)0
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs (renamed from compiler/rustc_typeck/src/check/upvar.rs)28
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs (renamed from compiler/rustc_typeck/src/check/writeback.rs)79
99 files changed, 6142 insertions, 4472 deletions
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 69ad623b7..129f8d235 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index e7c26bd72..4ef4aad90 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -314,74 +314,75 @@ pub enum Res<Id = hir::HirId> {
/// **Belongs to the type namespace.**
PrimTy(hir::PrimTy),
- /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
- /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
+ /// The `Self` type, as used within a trait.
+ ///
+ /// **Belongs to the type namespace.**
+ ///
+ /// See the examples on [`Res::SelfTyAlias`] for details.
+ SelfTyParam {
+ /// The trait this `Self` is a generic parameter for.
+ trait_: DefId,
+ },
+
+ /// The `Self` type, as used somewhere other than within a trait.
///
/// **Belongs to the type namespace.**
///
/// Examples:
/// ```
- /// struct Bar(Box<Self>);
- /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
+ /// struct Bar(Box<Self>); // SelfTyAlias
///
/// trait Foo {
- /// fn foo() -> Box<Self>;
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
+ /// fn foo() -> Box<Self>; // SelfTyParam
/// }
///
/// impl Bar {
/// fn blah() {
- /// let _: Self;
- /// // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
+ /// let _: Self; // SelfTyAlias
/// }
/// }
///
/// impl Foo for Bar {
- /// fn foo() -> Box<Self> {
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
- /// let _: Self;
- /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+ /// fn foo() -> Box<Self> { // SelfTyAlias
+ /// let _: Self; // SelfTyAlias
///
/// todo!()
/// }
/// }
/// ```
- ///
/// *See also [`Res::SelfCtor`].*
///
- /// -----
- ///
- /// HACK(min_const_generics): self types also have an optional requirement to **not** mention
- /// any generic parameters to allow the following with `min_const_generics`:
- /// ```
- /// # struct Foo;
- /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
- ///
- /// struct Bar([u8; baz::<Self>()]);
- /// const fn baz<T>() -> usize { 10 }
- /// ```
- /// We do however allow `Self` in repeat expression even if it is generic to not break code
- /// which already works on stable while causing the `const_evaluatable_unchecked` future compat
- /// lint:
- /// ```
- /// fn foo<T>() {
- /// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
- /// }
- /// ```
- // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
- SelfTy {
- /// The trait this `Self` is a generic arg for.
- trait_: Option<DefId>,
+ SelfTyAlias {
/// The item introducing the `Self` type alias. Can be used in the `type_of` query
- /// to get the underlying type. Additionally whether the `Self` type is disallowed
- /// from mentioning generics (i.e. when used in an anonymous constant).
- alias_to: Option<(DefId, bool)>,
- },
+ /// to get the underlying type.
+ alias_to: DefId,
- /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
- ///
- /// **Belongs to the type namespace.**
- ToolMod,
+ /// Whether the `Self` type is disallowed from mentioning generics (i.e. when used in an
+ /// anonymous constant).
+ ///
+ /// HACK(min_const_generics): self types also have an optional requirement to **not**
+ /// mention any generic parameters to allow the following with `min_const_generics`:
+ /// ```
+ /// # struct Foo;
+ /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+ ///
+ /// struct Bar([u8; baz::<Self>()]);
+ /// const fn baz<T>() -> usize { 10 }
+ /// ```
+ /// We do however allow `Self` in repeat expression even if it is generic to not break code
+ /// which already works on stable while causing the `const_evaluatable_unchecked` future
+ /// compat lint:
+ /// ```
+ /// fn foo<T>() {
+ /// let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+ /// }
+ /// ```
+ // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
+ forbid_generic: bool,
+
+ /// Is this within an `impl Foo for bar`?
+ is_trait_impl: bool,
+ },
// Value namespace
/// The `Self` constructor, along with the [`DefId`]
@@ -389,7 +390,7 @@ pub enum Res<Id = hir::HirId> {
///
/// **Belongs to the value namespace.**
///
- /// *See also [`Res::SelfTy`].*
+ /// *See also [`Res::SelfTyParam`] and [`Res::SelfTyAlias`].*
SelfCtor(DefId),
/// A local variable or function parameter.
@@ -397,6 +398,11 @@ pub enum Res<Id = hir::HirId> {
/// **Belongs to the value namespace.**
Local(Id),
+ /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
+ ///
+ /// **Belongs to the type namespace.**
+ ToolMod,
+
// Macro namespace
/// An attribute that is *not* implemented via macro.
/// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives,
@@ -458,6 +464,16 @@ impl PartialRes {
pub fn unresolved_segments(&self) -> usize {
self.unresolved_segments
}
+
+ #[inline]
+ pub fn full_res(&self) -> Option<Res<NodeId>> {
+ (self.unresolved_segments == 0).then_some(self.base_res)
+ }
+
+ #[inline]
+ pub fn expect_full_res(&self) -> Res<NodeId> {
+ self.full_res().expect("unexpected unresolved segments")
+ }
}
/// Different kinds of symbols can coexist even if they share the same textual name.
@@ -606,7 +622,8 @@ impl<Id> Res<Id> {
Res::Local(..)
| Res::PrimTy(..)
- | Res::SelfTy { .. }
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::SelfCtor(..)
| Res::ToolMod
| Res::NonMacroAttr(..)
@@ -629,7 +646,7 @@ impl<Id> Res<Id> {
Res::SelfCtor(..) => "self constructor",
Res::PrimTy(..) => "builtin type",
Res::Local(..) => "local variable",
- Res::SelfTy { .. } => "self type",
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type",
Res::ToolMod => "tool module",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::Err => "unresolved item",
@@ -652,7 +669,10 @@ impl<Id> Res<Id> {
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)),
- Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+ Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+ }
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
@@ -665,7 +685,10 @@ impl<Id> Res<Id> {
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)?),
- Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
+ Res::SelfTyParam { trait_ } => Res::SelfTyParam { trait_ },
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl } => {
+ Res::SelfTyAlias { alias_to, forbid_generic, is_trait_impl }
+ }
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
Res::Err => Res::Err,
@@ -692,7 +715,9 @@ impl<Id> Res<Id> {
pub fn ns(&self) -> Option<Namespace> {
match self {
Res::Def(kind, ..) => kind.ns(),
- Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
+ Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => {
+ Some(Namespace::TypeNS)
+ }
Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
Res::Err => None,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a8436ea64..ef00c1ffc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,6 @@
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::DefId;
-pub(crate) use crate::hir_id::{HirId, ItemLocalId};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId, OwnerId};
use crate::intravisit::FnKind;
use crate::LangItem;
@@ -731,6 +731,7 @@ pub enum PredicateOrigin {
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
#[derive(Debug, HashStable_Generic)]
pub struct WhereBoundPredicate<'hir> {
+ pub hir_id: HirId,
pub span: Span,
/// Origin of the predicate.
pub origin: PredicateOrigin,
@@ -2206,14 +2207,14 @@ pub struct FnSig<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct TraitItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl TraitItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2224,7 +2225,7 @@ impl TraitItemId {
#[derive(Debug, HashStable_Generic)]
pub struct TraitItem<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: TraitItemKind<'hir>,
pub span: Span,
@@ -2235,11 +2236,11 @@ impl TraitItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn trait_item_id(&self) -> TraitItemId {
- TraitItemId { def_id: self.def_id }
+ TraitItemId { owner_id: self.owner_id }
}
}
@@ -2270,14 +2271,14 @@ pub enum TraitItemKind<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ImplItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ImplItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2285,7 +2286,7 @@ impl ImplItemId {
#[derive(Debug, HashStable_Generic)]
pub struct ImplItem<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: ImplItemKind<'hir>,
pub defaultness: Defaultness,
@@ -2297,11 +2298,11 @@ impl ImplItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn impl_item_id(&self) -> ImplItemId {
- ImplItemId { def_id: self.def_id }
+ ImplItemId { owner_id: self.owner_id }
}
}
@@ -2314,7 +2315,7 @@ pub enum ImplItemKind<'hir> {
/// An associated function implementation with the given signature and body.
Fn(FnSig<'hir>, BodyId),
/// An associated type.
- TyAlias(&'hir Ty<'hir>),
+ Type(&'hir Ty<'hir>),
}
// The name of the associated type for `Fn` return types.
@@ -2403,8 +2404,9 @@ impl<'hir> Ty<'hir> {
return None;
};
match path.res {
- Res::Def(DefKind::TyParam, def_id)
- | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)),
+ Res::Def(DefKind::TyParam, def_id) | Res::SelfTyParam { trait_: def_id } => {
+ Some((def_id, segment.ident))
+ }
_ => None,
}
}
@@ -2416,6 +2418,30 @@ impl<'hir> Ty<'hir> {
}
final_ty
}
+
+ pub fn find_self_aliases(&self) -> Vec<Span> {
+ use crate::intravisit::Visitor;
+ struct MyVisitor(Vec<Span>);
+ impl<'v> Visitor<'v> for MyVisitor {
+ fn visit_ty(&mut self, t: &'v Ty<'v>) {
+ if matches!(
+ &t.kind,
+ TyKind::Path(QPath::Resolved(
+ _,
+ Path { res: crate::def::Res::SelfTyAlias { .. }, .. },
+ ))
+ ) {
+ self.0.push(t.span);
+ return;
+ }
+ crate::intravisit::walk_ty(self, t);
+ }
+ }
+
+ let mut my_visitor = MyVisitor(vec![]);
+ my_visitor.visit_ty(self);
+ my_visitor.0
+ }
}
/// Not represented directly in the AST; referred to by name through a `ty_path`.
@@ -2888,14 +2914,14 @@ impl<'hir> VariantData<'hir> {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
pub struct ItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -2905,7 +2931,7 @@ impl ItemId {
#[derive(Debug, HashStable_Generic)]
pub struct Item<'hir> {
pub ident: Ident,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub kind: ItemKind<'hir>,
pub span: Span,
pub vis_span: Span,
@@ -2915,11 +2941,11 @@ impl Item<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn item_id(&self) -> ItemId {
- ItemId { def_id: self.def_id }
+ ItemId { owner_id: self.owner_id }
}
}
@@ -3132,14 +3158,14 @@ pub enum AssocItemKind {
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ForeignItemId {
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
}
impl ForeignItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
@@ -3160,7 +3186,7 @@ pub struct ForeignItemRef {
pub struct ForeignItem<'hir> {
pub ident: Ident,
pub kind: ForeignItemKind<'hir>,
- pub def_id: LocalDefId,
+ pub owner_id: OwnerId,
pub span: Span,
pub vis_span: Span,
}
@@ -3169,11 +3195,11 @@ impl ForeignItem<'_> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn foreign_item_id(&self) -> ForeignItemId {
- ForeignItemId { def_id: self.def_id }
+ ForeignItemId { owner_id: self.owner_id }
}
}
@@ -3263,12 +3289,12 @@ impl<'hir> OwnerNode<'hir> {
Node::generics(self.into())
}
- pub fn def_id(self) -> LocalDefId {
+ pub fn def_id(self) -> OwnerId {
match self {
- OwnerNode::Item(Item { def_id, .. })
- | OwnerNode::TraitItem(TraitItem { def_id, .. })
- | OwnerNode::ImplItem(ImplItem { def_id, .. })
- | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id,
+ OwnerNode::Item(Item { owner_id, .. })
+ | OwnerNode::TraitItem(TraitItem { owner_id, .. })
+ | OwnerNode::ImplItem(ImplItem { owner_id, .. })
+ | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id,
OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
}
}
@@ -3512,7 +3538,7 @@ impl<'hir> Node<'hir> {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
use super::*;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(Block<'_>, 48);
static_assert_size!(Body<'_>, 32);
static_assert_size!(Expr<'_>, 64);
@@ -3520,30 +3546,27 @@ mod size_asserts {
static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
- #[cfg(not(bootstrap))]
static_assert_size!(GenericArg<'_>, 24);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
- #[cfg(not(bootstrap))]
static_assert_size!(ImplItem<'_>, 80);
- #[cfg(not(bootstrap))]
static_assert_size!(ImplItemKind<'_>, 32);
static_assert_size!(Item<'_>, 80);
static_assert_size!(ItemKind<'_>, 48);
static_assert_size!(Local<'_>, 64);
static_assert_size!(Param<'_>, 32);
static_assert_size!(Pat<'_>, 72);
+ static_assert_size!(Path<'_>, 40);
+ static_assert_size!(PathSegment<'_>, 48);
static_assert_size!(PatKind<'_>, 48);
- static_assert_size!(Path<'_>, 48);
- static_assert_size!(PathSegment<'_>, 56);
static_assert_size!(QPath<'_>, 24);
+ static_assert_size!(Res, 12);
static_assert_size!(Stmt<'_>, 32);
static_assert_size!(StmtKind<'_>, 16);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItem<'_>, 88);
- #[cfg(not(bootstrap))]
static_assert_size!(TraitItemKind<'_>, 48);
static_assert_size!(Ty<'_>, 48);
static_assert_size!(TyKind<'_>, 32);
+ // tidy-alphabetical-end
}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 84b0740c7..752f760ea 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,6 +1,43 @@
-use crate::def_id::{LocalDefId, CRATE_DEF_ID};
+use crate::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::{def_id::DefPathHash, HashStableContext};
use std::fmt;
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub struct OwnerId {
+ pub def_id: LocalDefId,
+}
+
+impl From<OwnerId> for HirId {
+ fn from(owner: OwnerId) -> HirId {
+ HirId { owner, local_id: ItemLocalId::from_u32(0) }
+ }
+}
+
+impl OwnerId {
+ #[inline]
+ pub fn to_def_id(self) -> DefId {
+ self.def_id.to_def_id()
+ }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for OwnerId {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+ }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
+ type KeyType = DefPathHash;
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+ hcx.def_path_hash(self.to_def_id())
+ }
+}
+
/// Uniquely identifies a node in the HIR of the current crate. It is
/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing
/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"),
@@ -15,22 +52,23 @@ use std::fmt;
#[derive(Encodable, Decodable, HashStable_Generic)]
#[rustc_pass_by_value]
pub struct HirId {
- pub owner: LocalDefId,
+ pub owner: OwnerId,
pub local_id: ItemLocalId,
}
impl HirId {
/// Signal local id which should never be used.
- pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID };
+ pub const INVALID: HirId =
+ HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::INVALID };
#[inline]
- pub fn expect_owner(self) -> LocalDefId {
+ pub fn expect_owner(self) -> OwnerId {
assert_eq!(self.local_id.index(), 0);
self.owner
}
#[inline]
- pub fn as_owner(self) -> Option<LocalDefId> {
+ pub fn as_owner(self) -> Option<OwnerId> {
if self.local_id.index() == 0 { Some(self.owner) } else { None }
}
@@ -41,11 +79,14 @@ impl HirId {
#[inline]
pub fn make_owner(owner: LocalDefId) -> Self {
- Self { owner, local_id: ItemLocalId::from_u32(0) }
+ Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) }
}
pub fn index(self) -> (usize, usize) {
- (rustc_index::vec::Idx::index(self.owner), rustc_index::vec::Idx::index(self.local_id))
+ (
+ rustc_index::vec::Idx::index(self.owner.def_id),
+ rustc_index::vec::Idx::index(self.local_id),
+ )
}
}
@@ -94,4 +135,7 @@ impl ItemLocalId {
}
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
-pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
+pub const CRATE_HIR_ID: HirId =
+ HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };
+
+pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 8f5f314ec..be77e6fd3 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -847,20 +847,28 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
) {
match *predicate {
WherePredicate::BoundPredicate(WhereBoundPredicate {
+ hir_id,
ref bounded_ty,
bounds,
bound_generic_params,
- ..
+ origin: _,
+ span: _,
}) => {
+ visitor.visit_id(hir_id);
visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
- WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
+ WherePredicate::RegionPredicate(WhereRegionPredicate {
+ ref lifetime,
+ bounds,
+ span: _,
+ in_where_clause: _,
+ }) => {
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_param_bound, bounds);
}
- WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
+ WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span: _ }) => {
visitor.visit_ty(lhs_ty);
visitor.visit_ty(rhs_ty);
}
@@ -904,7 +912,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+ let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
let hir_id = trait_item.hir_id();
visitor.visit_ident(ident);
visitor.visit_generics(&generics);
@@ -944,7 +952,7 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
let ImplItem {
- def_id: _,
+ owner_id: _,
ident,
ref generics,
ref kind,
@@ -971,7 +979,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
impl_item.hir_id(),
);
}
- ImplItemKind::TyAlias(ref ty) => {
+ ImplItemKind::Type(ref ty) => {
visitor.visit_id(impl_item.hir_id());
visitor.visit_ty(ty);
}
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 946da9265..1c4aa420c 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,8 +4,7 @@
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
-#![feature(const_btree_new)]
-#![cfg_attr(bootstrap, feature(let_else))]
+#![feature(const_btree_len)]
#![feature(once_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 5b9c42686..23423e8f3 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -20,7 +20,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
- let def_path_hash = self.owner.to_stable_hash_key(hcx);
+ let def_path_hash = self.owner.def_id.to_stable_hash_key(hcx);
(def_path_hash, self.local_id)
}
}
@@ -49,7 +49,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -58,7 +58,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -67,7 +67,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -76,7 +76,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index cae29c1d3..0761d8cdb 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "rustc_typeck"
+name = "rustc_hir_analysis"
version = "0.0.0"
edition = "2021"
@@ -26,7 +26,6 @@ rustc_span = { path = "../rustc_span" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/README.md b/compiler/rustc_hir_analysis/README.md
index b61dbd8c9..b61dbd8c9 100644
--- a/compiler/rustc_typeck/README.md
+++ b/compiler/rustc_hir_analysis/README.md
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index a9152bdc5..a9152bdc5 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index afac75de2..47915b4bd 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -83,9 +83,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Def(DefKind::TyParam, src_def_id) => {
if let Some(param_local_id) = param.def_id.as_local() {
let param_name = tcx.hir().ty_param_name(param_local_id);
- let param_type = tcx.infer_ctxt().enter(|infcx| {
- infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
- });
+ let infcx = tcx.infer_ctxt().build();
+ let param_type =
+ infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
if param_type.is_suggestable(tcx, false) {
err.span_suggestion(
tcx.def_span(src_def_id),
@@ -448,8 +448,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
- if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
- Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
+ if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
+ Self::prohibit_assoc_ty_binding(tcx, b.span);
}
let explicit_late_bound =
@@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(),
multispan,
- |lint| {
- lint.build(msg).emit();
- },
+ msg,
+ |lint| lint,
);
}
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 4bf9562e2..38f195dab 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -26,7 +26,7 @@ use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_middle::middle::stability::AllowUnstable;
-use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::DynKind;
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
@@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -275,10 +275,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment.args(),
item_segment.infer_args,
None,
+ None,
);
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
-
- if let Some(b) = assoc_bindings.first() {
+ if let Some(b) = item_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
@@ -326,6 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
+ constness: Option<ty::BoundConstness>,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
@@ -365,7 +365,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// here and so associated type bindings will be handled regardless of whether there are any
// non-`Self` generic parameters.
if generics.params.is_empty() {
- return (tcx.intern_substs(&[]), arg_count);
+ return (tcx.intern_substs(parent_substs), arg_count);
}
struct SubstsForAstPathCtxt<'a, 'tcx> {
@@ -536,6 +536,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&mut substs_ctx,
);
+ if let Some(ty::BoundConstness::ConstIfConst) = constness
+ && generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
+ {
+ tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
+ }
+
(substs, arg_count)
}
@@ -584,9 +590,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_bindings
}
- pub(crate) fn create_substs_for_associated_item(
+ pub fn create_substs_for_associated_item(
&self,
- tcx: TyCtxt<'tcx>,
span: Span,
item_def_id: DefId,
item_segment: &hir::PathSegment<'_>,
@@ -596,28 +601,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"create_substs_for_associated_item(span: {:?}, item_def_id: {:?}, item_segment: {:?}",
span, item_def_id, item_segment
);
- if tcx.generics_of(item_def_id).params.is_empty() {
- self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
-
- parent_substs
- } else {
- let (args, _) = self.create_substs_for_ast_path(
- span,
- item_def_id,
- parent_substs,
- item_segment,
- item_segment.args(),
- item_segment.infer_args,
- None,
- );
-
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args());
- if let Some(b) = assoc_bindings.first() {
- Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
- }
+ let (args, _) = self.create_substs_for_ast_path(
+ span,
+ item_def_id,
+ parent_substs,
+ item_segment,
+ item_segment.args(),
+ item_segment.infer_args,
+ None,
+ None,
+ );
- args
+ if let Some(b) = item_segment.args().bindings.first() {
+ Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
+
+ args
}
/// Instantiates the path for the given trait reference, assuming that it's
@@ -630,6 +629,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
+ constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
@@ -639,6 +639,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
+ Some(constness),
)
}
@@ -665,6 +666,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args,
infer_args,
Some(self_ty),
+ Some(constness),
);
let tcx = self.tcx();
@@ -690,6 +692,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
speculative,
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
+ constness,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@@ -793,6 +796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
is_impl: bool,
+ constness: Option<ty::BoundConstness>,
) -> ty::TraitRef<'tcx> {
let (substs, _) = self.create_substs_for_ast_trait_ref(
span,
@@ -800,9 +804,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_segment,
is_impl,
+ constness,
);
- let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
- if let Some(b) = assoc_bindings.first() {
+ if let Some(b) = trait_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
ty::TraitRef::new(trait_def_id, substs)
@@ -816,6 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
is_impl: bool,
+ constness: Option<ty::BoundConstness>,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
@@ -827,6 +832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait_segment.args(),
trait_segment.infer_args,
Some(self_ty),
+ constness,
)
}
@@ -1038,6 +1044,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
+ constness: ty::BoundConstness,
) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
@@ -1127,17 +1134,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
- tcx,
path_span,
assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
- debug!(
- "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
- substs_trait_ref_and_assoc_item
- );
+ debug!(?substs_trait_ref_and_assoc_item);
ty::ProjectionTy {
item_def_id: assoc_item.def_id,
@@ -1158,8 +1161,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
- debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
- debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+ debug!(?late_bound_in_trait_ref);
+ debug!(?late_bound_in_ty);
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
@@ -1660,6 +1663,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
+ #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
fn one_bound_for_assoc_type<I>(
&self,
all_candidates: impl Fn() -> I,
@@ -1689,10 +1693,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return Err(reported);
}
};
- debug!("one_bound_for_assoc_type: bound = {:?}", bound);
+ debug!(?bound);
if let Some(bound2) = next_cand {
- debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+ debug!(?bound2);
let is_equality = is_equality();
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
@@ -1788,6 +1792,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// parameter or `Self`.
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
+ #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
pub fn associated_path_to_ty(
&self,
hir_ref_id: hir::HirId,
@@ -1805,8 +1810,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Err
};
- debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
-
// Check if we have an enum variant.
let mut variant_resolution = None;
if let ty::Adt(adt_def, _) = qself_ty.kind() {
@@ -1910,7 +1913,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&qself_ty.kind(), qself_res) {
- (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
+ (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// trait reference.
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
@@ -1929,8 +1932,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
(
&ty::Param(_),
- Res::SelfTy { trait_: Some(param_did), alias_to: None }
- | Res::Def(DefKind::TyParam, param_did),
+ Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
_ => {
let reported = if variant_resolution.is_some() {
@@ -2023,30 +2025,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
if let Some(variant_def_id) = variant_resolution {
- tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
- let mut err = lint.build("ambiguous associated item");
- let mut could_refer_to = |kind: DefKind, def_id, also| {
- let note_msg = format!(
- "`{}` could{} refer to the {} defined here",
- assoc_ident,
- also,
- kind.descr(def_id)
- );
- err.span_note(tcx.def_span(def_id), &note_msg);
- };
+ tcx.struct_span_lint_hir(
+ AMBIGUOUS_ASSOCIATED_ITEMS,
+ hir_ref_id,
+ span,
+ "ambiguous associated item",
+ |lint| {
+ let mut could_refer_to = |kind: DefKind, def_id, also| {
+ let note_msg = format!(
+ "`{}` could{} refer to the {} defined here",
+ assoc_ident,
+ also,
+ kind.descr(def_id)
+ );
+ lint.span_note(tcx.def_span(def_id), &note_msg);
+ };
- could_refer_to(DefKind::Variant, variant_def_id, "");
- could_refer_to(kind, item.def_id, " also");
+ could_refer_to(DefKind::Variant, variant_def_id, "");
+ could_refer_to(kind, item.def_id, " also");
- err.span_suggestion(
- span,
- "use fully-qualified syntax",
- format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
- Applicability::MachineApplicable,
- );
+ lint.span_suggestion(
+ span,
+ "use fully-qualified syntax",
+ format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+ Applicability::MachineApplicable,
+ );
- err.emit();
- });
+ lint
+ },
+ );
}
Ok((ty, kind, item.def_id))
}
@@ -2058,6 +2065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'_>,
item_segment: &hir::PathSegment<'_>,
+ constness: ty::BoundConstness,
) -> Ty<'tcx> {
let tcx = self.tcx();
@@ -2102,11 +2110,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: self_type={:?}", self_ty);
- let trait_ref =
- self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
+ let trait_ref = self.ast_path_to_mono_trait_ref(
+ span,
+ trait_def_id,
+ self_ty,
+ trait_segment,
+ false,
+ Some(constness),
+ );
let item_substs = self.create_substs_for_associated_item(
- tcx,
span,
item_def_id,
item_segment,
@@ -2217,8 +2230,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
- if let [binding, ..] = segment.args().bindings {
- Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+ if let Some(b) = segment.args().bindings.first() {
+ Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
return true;
}
}
@@ -2426,7 +2439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
}
- Res::SelfTy { trait_: Some(_), alias_to: None } => {
+ Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments.iter(), |err| {
@@ -2441,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
});
tcx.types.self_param
}
- Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
+ Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
// Try to evaluate any array length constants.
@@ -2543,12 +2556,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
+ // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
+ let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
self.qpath_to_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
+ constness,
)
}
Res::PrimTy(prim_ty) => {
@@ -2641,7 +2661,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
- let def_id = item_id.def_id.to_def_id();
+ let def_id = item_id.owner_id.to_def_id();
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
@@ -2667,6 +2687,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&GenericArgs::none(),
true,
None,
+ None,
);
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
.subst(tcx, substs)
@@ -2775,6 +2796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
pub fn ty_of_fn(
&self,
hir_id: hir::HirId,
@@ -2784,8 +2806,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
generics: Option<&hir::Generics<'_>>,
hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
- debug!("ty_of_fn");
-
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(hir_id);
debug!(?bound_vars);
@@ -2835,7 +2855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
};
- debug!("ty_of_fn: output_ty={:?}", output_ty);
+ debug!(?output_ty);
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
@@ -2912,8 +2932,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
- let trait_ref =
- self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+ let trait_ref = self.instantiate_mono_trait_ref(
+ i.of_trait.as_ref()?,
+ self.ast_ty_to_ty(i.self_ty),
+ ty::BoundConstness::NotConst,
+ );
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
tcx,
@@ -3009,7 +3032,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
let tcx = self.tcx();
- let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
+ let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
@@ -3060,24 +3083,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map_or(false, |s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
- let sugg = Vec::from_iter([
- (
- self_ty.span.shrink_to_lo(),
- format!(
- "{}dyn {}",
- if needs_bracket { "<" } else { "" },
- if is_global { "(" } else { "" },
- ),
+
+ let mut sugg = Vec::from_iter([(
+ self_ty.span.shrink_to_lo(),
+ format!(
+ "{}dyn {}",
+ if needs_bracket { "<" } else { "" },
+ if is_global { "(" } else { "" },
),
- (
+ )]);
+
+ if is_global || needs_bracket {
+ sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
- ),
- ]);
+ ));
+ }
+
if self_ty.span.edition() >= Edition::Edition2021 {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
@@ -3093,15 +3119,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
BARE_TRAIT_OBJECTS,
self_ty.hir_id,
self_ty.span,
+ msg,
|lint| {
- let mut diag = lint.build(msg);
- diag.multipart_suggestion_verbose(
+ lint.multipart_suggestion_verbose(
"use `dyn`",
sugg,
Applicability::MachineApplicable,
);
- self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
- diag.emit();
+ self.maybe_lint_blanket_trait_impl(&self_ty, lint);
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 6a28bb16a..6a28bb16a 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d6fa74c87..b70ac0205 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,8 +1,7 @@
use crate::check::intrinsicck::InlineAsmCtxt;
-use super::coercion::CoerceMany;
use super::compare_method::check_type_bounds;
-use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::compare_method::{compare_impl_method, compare_ty_impl};
use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
@@ -10,10 +9,8 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
@@ -29,13 +26,12 @@ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVE
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
-use rustc_ty_utils::representability::{self, Representability};
use std::ops::ControlFlow;
-pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
+pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
match tcx.sess.target.is_abi_supported(abi) {
Some(true) => (),
Some(false) => {
@@ -48,9 +44,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
.emit();
}
None => {
- tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
- lint.build("use of calling convention not supported on this target").emit();
- });
+ tcx.struct_span_lint_hir(
+ UNSUPPORTED_CALLING_CONVENTIONS,
+ hir_id,
+ span,
+ "use of calling convention not supported on this target",
+ |lint| lint,
+ );
}
}
@@ -66,318 +66,10 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
}
}
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-#[instrument(skip(inherited, body), level = "debug")]
-pub(super) fn check_fn<'a, 'tcx>(
- inherited: &'a Inherited<'a, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- fn_sig: ty::FnSig<'tcx>,
- decl: &'tcx hir::FnDecl<'tcx>,
- fn_id: hir::HirId,
- body: &'tcx hir::Body<'tcx>,
- can_be_generator: Option<hir::Movability>,
- return_type_pre_known: bool,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
- // Create the function context. This is either derived from scratch or,
- // in the case of closures, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
- fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
- fcx.return_type_pre_known = return_type_pre_known;
-
- let tcx = fcx.tcx;
- let hir = tcx.hir();
-
- let declared_ret_ty = fn_sig.output();
-
- let ret_ty =
- fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
- declared_ret_ty,
- body.value.hir_id,
- decl.output.span(),
- param_env,
- ));
- // If we replaced declared_ret_ty with infer vars, then we must be inferring
- // an opaque type, so set a flag so we can improve diagnostics.
- fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
-
- fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
-
- let span = body.value.span;
-
- fn_maybe_err(tcx, span, fn_sig.abi);
-
- if fn_sig.abi == Abi::RustCall {
- let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
- let err = || {
- let item = match tcx.hir().get(fn_id) {
- Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(header, ..), ..
- }) => Some(header),
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(header, ..),
- ..
- }) => Some(header),
- // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
- node => bug!("Item being checked wasn't a function/closure: {:?}", node),
- };
-
- if let Some(header) = item {
- tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
- }
- };
-
- if fn_sig.inputs().len() != expected_args {
- err()
- } else {
- // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
- // This will probably require wide-scale changes to support a TupleKind obligation
- // We can't resolve this without knowing the type of the param
- if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
- err()
- }
- }
- }
-
- if body.generator_kind.is_some() && can_be_generator.is_some() {
- let yield_ty = fcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
- fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
- // Resume type defaults to `()` if the generator has no argument.
- let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
- fcx.resume_yield_tys = Some((resume_ty, yield_ty));
- }
-
- GatherLocalsVisitor::new(&fcx).visit_body(body);
-
- // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
- // (as it's created inside the body itself, not passed in from outside).
- let maybe_va_list = if fn_sig.c_variadic {
- let span = body.params.last().unwrap().span;
- let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
- let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
- Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
- } else {
- None
- };
-
- // Add formal parameters.
- let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
- let inputs_fn = fn_sig.inputs().iter().copied();
- for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
- // Check the pattern.
- let ty_span = try { inputs_hir?.get(idx)?.span };
- fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
- // Check that argument is Sized.
- // The check for a non-trivial pattern is a hack to avoid duplicate warnings
- // for simple cases like `fn foo(x: Trait)`,
- // where we would error once on the parameter as a whole, and once on the binding `x`.
- if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
- fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
- }
-
- fcx.write_ty(param.hir_id, param_ty);
- }
-
- inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
- fcx.in_tail_expr = true;
- if let ty::Dynamic(..) = declared_ret_ty.kind() {
- // FIXME: We need to verify that the return type is `Sized` after the return expression has
- // been evaluated so that we have types available for all the nodes being returned, but that
- // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
- // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
- // while keeping the current ordering we will ignore the tail expression's type because we
- // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
- // because we will trigger "unreachable expression" lints unconditionally.
- // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
- // case that a newcomer might make, returning a bare trait, and in that case we populate
- // the tail expression's type so that the suggestion will be correct, but ignore all other
- // possible cases.
- fcx.check_expr(&body.value);
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- } else {
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- fcx.check_return_expr(&body.value, false);
- }
- fcx.in_tail_expr = false;
-
- // We insert the deferred_generator_interiors entry after visiting the body.
- // This ensures that all nested generators appear before the entry of this generator.
- // resolve_generator_interiors relies on this property.
- let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
- let interior = fcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
- fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
- let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
- Some(GeneratorTypes {
- resume_ty,
- yield_ty,
- interior,
- movability: can_be_generator.unwrap(),
- })
- } else {
- None
- };
-
- // Finalize the return check by taking the LUB of the return types
- // we saw and assigning it to the expected return type. This isn't
- // really expected to fail, since the coercions would have failed
- // earlier when trying to find a LUB.
- let coercion = fcx.ret_coercion.take().unwrap().into_inner();
- let mut actual_return_ty = coercion.complete(&fcx);
- debug!("actual_return_ty = {:?}", actual_return_ty);
- if let ty::Dynamic(..) = declared_ret_ty.kind() {
- // We have special-cased the case where the function is declared
- // `-> dyn Foo` and we don't actually relate it to the
- // `fcx.ret_coercion`, so just substitute a type variable.
- actual_return_ty =
- fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
- debug!("actual_return_ty replaced with {:?}", actual_return_ty);
- }
-
- // HACK(oli-obk, compiler-errors): We should be comparing this against
- // `declared_ret_ty`, but then anything uninferred would be inferred to
- // the opaque type itself. That again would cause writeback to assume
- // we have a recursive call site and do the sadly stabilized fallback to `()`.
- fcx.demand_suptype(span, ret_ty, actual_return_ty);
-
- // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
- if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
- && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
- // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
- if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
- && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
- (fcx, gen_ty)
-}
-
-fn check_panic_info_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(panic_info_did) = tcx.lang_items().panic_info() else {
- tcx.sess.err("language item required, but not found: `panic_info`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_panic_info = match *inputs[0].kind() {
- ty::Ref(region, ty, mutbl) => match *ty.kind() {
- ty::Adt(ref adt, _) => {
- adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
- }
- _ => false,
- },
- _ => false,
- };
-
- if !arg_is_panic_info {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "should have no const parameters");
- }
-}
-
-fn check_alloc_error_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
- tcx.sess.err("language item required, but not found: `alloc_layout`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_alloc_layout = match inputs[0].kind() {
- ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
- _ => false,
- };
-
- if !arg_is_alloc_layout {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess
- .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
- }
-}
-
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_representable(tcx, span, def_id);
if def.repr().simd() {
check_simd(tcx, span, def_id);
@@ -391,7 +83,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_representable(tcx, span, def_id);
check_transparent(tcx, span, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
@@ -423,7 +114,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
_ => {
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
- || ty.is_copy_modulo_regions(tcx.at(span), param_env)
+ || ty.is_copy_modulo_regions(tcx, param_env)
}
}
}
@@ -510,10 +201,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
UNINHABITED_STATIC,
tcx.hir().local_def_id_to_hir_id(def_id),
span,
+ "static of uninhabited type",
|lint| {
- lint.build("static of uninhabited type")
+ lint
.note("uninhabited statics cannot be initialized, and any access would be an immediate error")
- .emit();
},
);
}
@@ -521,23 +212,33 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
/// projections that would result in "inheriting lifetimes".
-pub(super) fn check_opaque<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
- substs: SubstsRef<'tcx>,
- origin: &hir::OpaqueTyOrigin,
-) {
- let span = tcx.def_span(def_id);
- check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
- if tcx.type_of(def_id).references_error() {
+fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
+ let item = tcx.hir().item(id);
+ let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
+ tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
+ return;
+ };
+
+ // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
+ // `async-std` (and `pub async fn` in general).
+ // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
+ // See https://github.com/rust-lang/rust/issues/75100
+ if tcx.sess.opts.actually_rustdoc {
+ return;
+ }
+
+ let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
+ let span = tcx.def_span(item.owner_id.def_id);
+
+ check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ if tcx.type_of(item.owner_id.def_id).references_error() {
return;
}
- if check_opaque_for_cycles(tcx, def_id, substs, span, origin).is_err() {
+ if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
return;
}
- check_opaque_meets_bounds(tcx, def_id, substs, span, origin);
+ check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
}
-
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
@@ -609,9 +310,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
- [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
- let impl_ty_name =
- impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+ [PathSegment { res: Res::SelfTyParam { .. }, .. }] => {
+ let impl_ty_name = None;
+ self.selftys.push((path.span, impl_ty_name));
+ }
+ [PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => {
+ let impl_ty_name = Some(self.tcx.def_path_str(*def_id));
self.selftys.push((path.span, impl_ty_name));
}
_ => {}
@@ -701,10 +405,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
/// check those cases in the `param_env` of that function, which may have
/// bounds not on this opaque type:
///
-/// type X<T> = impl Clone
+/// ```ignore (illustrative)
+/// type X<T> = impl Clone;
/// fn f<T: Clone>(t: T) -> X<T> {
/// t
/// }
+/// ```
///
/// Without this check the above code is incorrectly accepted: we would ICE if
/// some tried, for example, to clone an `Option<X<&mut ()>>`.
@@ -716,8 +422,6 @@ fn check_opaque_meets_bounds<'tcx>(
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
- let hidden_type = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
@@ -725,76 +429,88 @@ fn check_opaque_meets_bounds<'tcx>(
};
let param_env = tcx.param_env(defining_use_anchor);
- tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
- move |infcx| {
- let ocx = ObligationCtxt::new(&infcx);
- let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+ let infcx = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
+ .build();
+ let ocx = ObligationCtxt::new(&infcx);
+ let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+
+ // `ReErased` regions appear in the "parent_substs" of closures/generators.
+ // We're ignoring them here and replacing them with fresh region variables.
+ // See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs.
+ //
+ // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it
+ // here rather than using ReErased.
+ let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs);
+ let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() {
+ ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)),
+ _ => re,
+ });
- let misc_cause = traits::ObligationCause::misc(span, hir_id);
+ let misc_cause = traits::ObligationCause::misc(span, hir_id);
- match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
- Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
- Err(ty_err) => {
- tcx.sess.delay_span_bug(
- span,
- &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
- );
- }
- }
+ match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
+ Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+ Err(ty_err) => {
+ tcx.sess.delay_span_bug(
+ span,
+ &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
+ );
+ }
+ }
- // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
- .to_predicate(tcx);
- ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- match origin {
- // Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
- // Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- defining_use_anchor,
- &outlives_environment,
- );
- }
- }
- // Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- },
- );
+ // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
+ ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ match origin {
+ // Checked when type checking the function containing them.
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+ // Can have different predicates to their defining use
+ hir::OpaqueTyOrigin::TyAlias => {
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(
+ defining_use_anchor,
+ &outlives_environment,
+ );
+ }
+ }
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
}
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
- id.def_id,
- tcx.def_path_str(id.def_id.to_def_id())
+ id.owner_id,
+ tcx.def_path_str(id.owner_id.to_def_id())
);
let _indenter = indenter();
- match tcx.def_kind(id.def_id) {
+ match tcx.def_kind(id.owner_id) {
DefKind::Static(..) => {
- tcx.ensure().typeck(id.def_id);
- maybe_check_static_with_link_section(tcx, id.def_id);
- check_static_inhabited(tcx, id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
+ maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
+ check_static_inhabited(tcx, id.owner_id.def_id);
}
DefKind::Const => {
- tcx.ensure().typeck(id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
}
DefKind::Enum => {
let item = tcx.hir().item(id);
let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
return;
};
- check_enum(tcx, &enum_definition.variants, item.def_id);
+ check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
@@ -802,12 +518,12 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
let hir::ItemKind::Impl(ref impl_) = it.kind else {
return;
};
- debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id);
- if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) {
+ debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
+ if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
check_impl_items_against_trait(
tcx,
it.span,
- it.def_id,
+ it.owner_id.def_id,
impl_trait_ref,
&impl_.items,
);
@@ -829,15 +545,15 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
fn_maybe_err(tcx, item.ident.span, abi);
}
hir::TraitItemKind::Type(.., Some(default)) => {
- let assoc_item = tcx.associated_item(item.def_id);
+ let assoc_item = tcx.associated_item(item.owner_id);
let trait_substs =
- InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
+ InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id());
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
+ ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
);
}
_ => {}
@@ -845,28 +561,28 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
}
DefKind::Struct => {
- check_struct(tcx, id.def_id);
+ check_struct(tcx, id.owner_id.def_id);
}
DefKind::Union => {
- check_union(tcx, id.def_id);
+ check_union(tcx, id.owner_id.def_id);
}
DefKind::OpaqueTy => {
- let item = tcx.hir().item(id);
- let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
- return;
- };
- // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
- // `async-std` (and `pub async fn` in general).
- // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
- // See https://github.com/rust-lang/rust/issues/75100
- if !tcx.sess.opts.actually_rustdoc {
- let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
- check_opaque(tcx, item.def_id, substs, &origin);
+ check_opaque(tcx, id);
+ }
+ DefKind::ImplTraitPlaceholder => {
+ let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
+ // Only check the validity of this opaque type if the function has a default body
+ if let hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
+ ..
+ }) = tcx.hir().get_by_def_id(parent.expect_local())
+ {
+ check_opaque(tcx, id);
}
}
DefKind::TyAlias => {
- let pty_ty = tcx.type_of(id.def_id);
- let generics = tcx.generics_of(id.def_id);
+ let pty_ty = tcx.type_of(id.owner_id);
+ let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);
}
DefKind::ForeignMod => {
@@ -888,7 +604,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
} else {
for item in items {
- let def_id = item.id.def_id;
+ let def_id = item.id.owner_id.def_id;
let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts();
if generics.params.len() - own_counts.lifetimes != 0 {
@@ -943,7 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
+ let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
@@ -1030,7 +746,7 @@ fn check_impl_items_against_trait<'tcx>(
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
for impl_item in impl_item_refs {
- let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+ let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
tcx.associated_item(trait_item_id)
} else {
@@ -1041,14 +757,10 @@ fn check_impl_items_against_trait<'tcx>(
let impl_item_full = tcx.hir().impl_item(impl_item.id);
match impl_item_full.kind {
hir::ImplItemKind::Const(..) => {
- // Find associated const definition.
- compare_const_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- );
+ let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
+ impl_item.id.owner_id.def_id,
+ ty_impl_item.trait_item_def_id.unwrap(),
+ ));
}
hir::ImplItemKind::Fn(..) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
@@ -1060,7 +772,7 @@ fn check_impl_items_against_trait<'tcx>(
opt_trait_span,
);
}
- hir::ImplItemKind::TyAlias(impl_ty) => {
+ hir::ImplItemKind::Type(impl_ty) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
compare_ty_impl(
tcx,
@@ -1148,27 +860,6 @@ fn check_impl_items_against_trait<'tcx>(
}
}
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
- let rty = tcx.type_of(item_def_id);
-
- // Check that it is possible to represent this type. This call identifies
- // (1) types that contain themselves and (2) types that contain a different
- // recursive type. It is only necessary to throw an error on those that
- // contain themselves. For case 2, there must be an inner type that will be
- // caught by case 1.
- match representability::ty_is_representable(tcx, rty, sp, None) {
- Representability::SelfRecursive(spans) => {
- recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
- return false;
- }
- Representability::Representable | Representability::ContainsRecursive => (),
- }
- true
-}
-
pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
let t = tcx.type_of(def_id);
if let ty::Adt(def, substs) = t.kind()
@@ -1434,6 +1125,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
+ "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
@@ -1441,10 +1133,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
"contains private fields"
};
let field_ty = tcx.def_path_str_with_substs(def_id, substs);
- lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+ lint
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
- .emit();
},
)
}
@@ -1489,7 +1180,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
}
}
- if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant {
+ if tcx.adt_def(def_id).repr().int.is_none() {
let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
@@ -1506,7 +1197,6 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
- check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def);
}
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 59d591acd..32f66b06f 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1,6 +1,6 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
@@ -12,14 +12,14 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{
self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal,
@@ -215,224 +215,220 @@ fn compare_predicate_entailment<'tcx>(
);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
+ debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
- let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
- for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
- let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
+ let mut selcx = traits::SelectionContext::new(&infcx);
+ let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
+ for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
+ let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
+ let traits::Normalized { value: predicate, obligations } =
+ traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
- ocx.register_obligations(obligations);
- let cause = ObligationCause::new(
- span,
- impl_m_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_m.def_id.expect_local(),
- trait_item_def_id: trait_m.def_id,
- kind: impl_m.kind,
- },
- );
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
- }
-
- // We now need to check that the signature of the impl method is
- // compatible with that of the trait method. We do this by
- // checking that `impl_fty <: trait_fty`.
- //
- // FIXME. Unfortunately, this doesn't quite work right now because
- // associated type normalization is not integrated into subtype
- // checks. For the comparison to be valid, we need to
- // normalize the associated types in the impl/trait methods
- // first. However, because function types bind regions, just
- // calling `normalize_associated_types_in` would have no effect on
- // any associated types appearing in the fn arguments or return
- // type.
-
- // Compute placeholder form of impl and trait method tys.
- let tcx = infcx.tcx;
-
- let mut wf_tys = FxHashSet::default();
-
- let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
- impl_m_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
+ ocx.register_obligations(obligations);
+ let cause = ObligationCause::new(
+ span,
+ impl_m_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_m.def_id.expect_local(),
+ trait_item_def_id: trait_m.def_id,
+ kind: impl_m.kind,
+ },
);
+ ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ }
- let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
- debug!("compare_impl_method: impl_fty={:?}", impl_fty);
-
- let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
- let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
-
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
- // We also have to add the normalized trait signature
- // as we don't normalize during implied bounds computation.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
-
- debug!("compare_impl_method: trait_fty={:?}", trait_fty);
-
- // FIXME: We'd want to keep more accurate spans than "the method signature" when
- // processing the comparison between the trait and impl fn, but we sadly lose them
- // and point at the whole signature when a trait bound or specific input or output
- // type would be more appropriate. In other places we have a `Vec<Span>`
- // corresponding to their `Vec<Predicate>`, but we don't have that here.
- // Fixing this would improve the output of test `issue-83765.rs`.
- let mut result = infcx
- .at(&cause, param_env)
- .sup(trait_fty, impl_fty)
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
-
- // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
- // RPITITs, we need to equate the output tys instead of just subtyping. If
- // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
- // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
- // fixed up to `ReEmpty`, and which is certainly not what we want.
- if trait_fty.has_infer_types() {
- result = result.and_then(|()| {
- infcx
- .at(&cause, param_env)
- .eq(trait_sig.output(), impl_sig.output())
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
- });
- }
+ // We now need to check that the signature of the impl method is
+ // compatible with that of the trait method. We do this by
+ // checking that `impl_fty <: trait_fty`.
+ //
+ // FIXME. Unfortunately, this doesn't quite work right now because
+ // associated type normalization is not integrated into subtype
+ // checks. For the comparison to be valid, we need to
+ // normalize the associated types in the impl/trait methods
+ // first. However, because function types bind regions, just
+ // calling `normalize_associated_types_in` would have no effect on
+ // any associated types appearing in the fn arguments or return
+ // type.
+
+ // Compute placeholder form of impl and trait method tys.
+ let tcx = infcx.tcx;
- if let Err(terr) = result {
- debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
+ let mut wf_tys = FxHashSet::default();
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+ let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ impl_m_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ );
- cause.span = impl_err_span;
+ let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
+ let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+ debug!("compare_impl_method: impl_fty={:?}", impl_fty);
+
+ let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
+ let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+
+ // Next, add all inputs and output as well-formed tys. Importantly,
+ // we have to do this before normalization, since the normalized ty may
+ // not contain the input parameters. See issue #87748.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
+ // We also have to add the normalized trait signature
+ // as we don't normalize during implied bounds computation.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+
+ debug!("compare_impl_method: trait_fty={:?}", trait_fty);
+
+ // FIXME: We'd want to keep more accurate spans than "the method signature" when
+ // processing the comparison between the trait and impl fn, but we sadly lose them
+ // and point at the whole signature when a trait bound or specific input or output
+ // type would be more appropriate. In other places we have a `Vec<Span>`
+ // corresponding to their `Vec<Predicate>`, but we don't have that here.
+ // Fixing this would improve the output of test `issue-83765.rs`.
+ let mut result = infcx
+ .at(&cause, param_env)
+ .sup(trait_fty, impl_fty)
+ .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
+
+ // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
+ // RPITITs, we need to equate the output tys instead of just subtyping. If
+ // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
+ // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
+ // fixed up to `ReEmpty`, and which is certainly not what we want.
+ if trait_fty.has_infer_types() {
+ result = result.and_then(|()| {
+ infcx
+ .at(&cause, param_env)
+ .eq(trait_sig.output(), impl_sig.output())
+ .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
+ });
+ }
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible type for trait",
- trait_m.name
- );
- match &terr {
- TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
- {
- let ty = trait_sig.inputs()[0];
- let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
- {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
- "&mut self".to_owned()
- }
- _ => format!("self: {ty}"),
- };
+ if let Err(terr) = result {
+ debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
- // span points only at the type `Box<Self`>, but we want to cover the whole
- // argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+ cause.span = impl_err_span;
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span(),
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name
+ );
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {ty}"),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ if trait_sig.inputs().len() == *i {
+ // Suggestion to change output type. We do not suggest in `async` functions
+ // to avoid complex logic or incorrect output.
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _)
+ if sig.header.asyncness == hir::IsAsync::NotAsync =>
+ {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
diag.span_suggestion(
- span,
- "change the self-receiver type to match the trait",
- sugg,
+ impl_err_span,
+ "change the parameter type to match the trait",
+ trait_ty,
Applicability::MachineApplicable,
);
}
- TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
- if trait_sig.inputs().len() == *i {
- // Suggestion to change output type. We do not suggest in `async` functions
- // to avoid complex logic or incorrect output.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _)
- if sig.header.asyncness == hir::IsAsync::NotAsync =>
- {
- let msg = "change the output type to match the trait";
- let ap = Applicability::MachineApplicable;
- match sig.decl.output {
- hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
- };
- } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
- diag.span_suggestion(
- impl_err_span,
- "change the parameter type to match the trait",
- trait_ty,
- Applicability::MachineApplicable,
- );
- }
- }
- _ => {}
}
+ _ => {}
+ }
- infcx.note_type_err(
- &mut diag,
- &cause,
- trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
- terr,
- false,
- false,
- );
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
- return Err(diag.emit());
- }
+ return Err(diag.emit());
+ }
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
- );
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
- );
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ );
+ infcx.check_region_obligations_and_report_errors(
+ impl_m.def_id.expect_local(),
+ &outlives_environment,
+ );
- Ok(())
- })
+ Ok(())
}
pub fn collect_trait_impl_trait_tys<'tcx>(
@@ -465,125 +461,173 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let trait_to_placeholder_substs =
impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
- let impl_return_ty = ocx.normalize(
- norm_cause.clone(),
- param_env,
- infcx
- .replace_bound_vars_with_fresh_vars(
- return_span,
- infer::HigherRankedType,
- tcx.fn_sig(impl_m.def_id),
- )
- .output(),
- );
+ let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id);
+ let impl_sig = ocx.normalize(
+ norm_cause.clone(),
+ param_env,
+ infcx.replace_bound_vars_with_fresh_vars(
+ return_span,
+ infer::HigherRankedType,
+ tcx.fn_sig(impl_m.def_id),
+ ),
+ );
+ let impl_return_ty = impl_sig.output();
- let mut collector =
- ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
- let unnormalized_trait_return_ty = tcx
- .liberate_late_bound_regions(
- impl_m.def_id,
- tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
- )
- .output()
- .fold_with(&mut collector);
- let trait_return_ty =
- ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_return_ty);
+ let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+ let unnormalized_trait_sig = tcx
+ .liberate_late_bound_regions(
+ impl_m.def_id,
+ tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
+ )
+ .fold_with(&mut collector);
+ let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+ let trait_return_ty = trait_sig.output();
- let wf_tys = FxHashSet::from_iter([unnormalized_trait_return_ty, trait_return_ty]);
+ let wf_tys = FxHashSet::from_iter(
+ unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+ );
- match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
- Err(terr) => {
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible return type for trait",
- trait_m.name
- );
- let hir = tcx.hir();
- infcx.note_type_err(
- &mut diag,
- &cause,
- hir.get_if_local(impl_m.def_id)
- .and_then(|node| node.fn_decl())
- .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_return_ty.into(),
- found: impl_return_ty.into(),
- })),
- terr,
- false,
- false,
- );
- return Err(diag.emit());
- }
+ match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
+ Ok(infer::InferOk { value: (), obligations }) => {
+ ocx.register_obligations(obligations);
}
+ Err(terr) => {
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span(),
+ E0053,
+ "method `{}` has an incompatible return type for trait",
+ trait_m.name
+ );
+ let hir = tcx.hir();
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ hir.get_if_local(impl_m.def_id)
+ .and_then(|node| node.fn_decl())
+ .map(|decl| (decl.output.span(), "return type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_return_ty.into(),
+ found: impl_return_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ }
+ }
- // Check that all obligations are satisfied by the implementation's
- // RPITs.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
+ // Unify the whole function signature. We need to do this to fully infer
+ // the lifetimes of the return type, but do this after unifying just the
+ // return types, since we want to avoid duplicating errors from
+ // `compare_predicate_entailment`.
+ match infcx
+ .at(&cause, param_env)
+ .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
+ {
+ Ok(infer::InferOk { value: (), obligations }) => {
+ ocx.register_obligations(obligations);
}
+ Err(terr) => {
+ let guar = tcx.sess.delay_span_bug(
+ return_span,
+ format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+ );
+ return Err(guar);
+ }
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
- );
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
- );
+ // Check that all obligations are satisfied by the implementation's
+ // RPITs.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- let mut collected_tys = FxHashMap::default();
- for (def_id, (ty, substs)) in collector.types {
- match infcx.fully_resolve(ty) {
- Ok(ty) => {
- // `ty` contains free regions that we created earlier while liberating the
- // trait fn signature. However, projection normalization expects `ty` to
- // contains `def_id`'s early-bound regions.
- let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
- debug!(?id_substs, ?substs);
- let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> = substs
- .iter()
- .enumerate()
- .map(|(index, arg)| (arg, id_substs[index]))
- .collect();
- debug!(?map);
-
- let ty = tcx.fold_regions(ty, |region, _| {
- if let ty::ReFree(_) = region.kind() {
- map[&region.into()].expect_region()
- } else {
- region
- }
- });
- debug!(%ty);
- collected_tys.insert(def_id, ty);
- }
- Err(err) => {
- tcx.sess.delay_span_bug(
- return_span,
- format!("could not fully resolve: {ty} => {err:?}"),
- );
- collected_tys.insert(def_id, tcx.ty_error());
- }
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(infcx),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ );
+ infcx.check_region_obligations_and_report_errors(
+ impl_m.def_id.expect_local(),
+ &outlives_environment,
+ );
+
+ let mut collected_tys = FxHashMap::default();
+ for (def_id, (ty, substs)) in collector.types {
+ match infcx.fully_resolve(ty) {
+ Ok(ty) => {
+ // `ty` contains free regions that we created earlier while liberating the
+ // trait fn signature. However, projection normalization expects `ty` to
+ // contains `def_id`'s early-bound regions.
+ let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+ debug!(?id_substs, ?substs);
+ let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
+ std::iter::zip(substs, id_substs).collect();
+ debug!(?map);
+
+ // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
+ // region substs that are synthesized during AST lowering. These are substs
+ // that are appended to the parent substs (trait and trait method). However,
+ // we're trying to infer the unsubstituted type value of the RPITIT inside
+ // the *impl*, so we can later use the impl's method substs to normalize
+ // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
+ //
+ // Due to the design of RPITITs, during AST lowering, we have no idea that
+ // an impl method corresponds to a trait method with RPITITs in it. Therefore,
+ // we don't have a list of early-bound region substs for the RPITIT in the impl.
+ // Since early region parameters are index-based, we can't just rebase these
+ // (trait method) early-bound region substs onto the impl, and there's no
+ // guarantee that the indices from the trait substs and impl substs line up.
+ // So to fix this, we subtract the number of trait substs and add the number of
+ // impl substs to *renumber* these early-bound regions to their corresponding
+ // indices in the impl's substitutions list.
+ //
+ // Also, we only need to account for a difference in trait and impl substs,
+ // since we previously enforce that the trait method and impl method have the
+ // same generics.
+ let num_trait_substs = trait_to_impl_substs.len();
+ let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
+ let ty = tcx.fold_regions(ty, |region, _| {
+ let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
+ let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
+ else {
+ tcx
+ .sess
+ .delay_span_bug(
+ return_span,
+ "expected ReFree to map to ReEarlyBound"
+ );
+ return tcx.lifetimes.re_static;
+ };
+ tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: e.def_id,
+ name: e.name,
+ index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
+ }))
+ });
+ debug!(%ty);
+ collected_tys.insert(def_id, ty);
+ }
+ Err(err) => {
+ tcx.sess.delay_span_bug(
+ return_span,
+ format!("could not fully resolve: {ty} => {err:?}"),
+ );
+ collected_tys.insert(def_id, tcx.ty_error());
}
}
+ }
- Ok(&*tcx.arena.alloc(collected_tys))
- })
+ Ok(&*tcx.arena.alloc(collected_tys))
}
struct ImplTraitInTraitCollector<'a, 'tcx> {
@@ -628,10 +672,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
});
self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
// Recurse into bounds
- for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
- let pred_span = pred.0.1;
-
- let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+ for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
ObligationCause::misc(self.span, self.body_id),
@@ -712,8 +753,8 @@ fn check_region_bounds_on_impl_item<'tcx>(
}
#[instrument(level = "debug", skip(infcx))]
-fn extract_spans_for_error_reporting<'a, 'tcx>(
- infcx: &infer::InferCtxt<'a, 'tcx>,
+fn extract_spans_for_error_reporting<'tcx>(
+ infcx: &infer::InferCtxt<'tcx>,
terr: TypeError<'_>,
cause: &ObligationCause<'tcx>,
impl_m: &ty::AssocItem,
@@ -768,16 +809,15 @@ fn compare_self_type<'tcx>(
let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
let param_env = ty::ParamEnv::reveal_all();
- tcx.infer_ctxt().enter(|infcx| {
- let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
- let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
- match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {self_arg_ty}"),
- }
- })
+ let infcx = tcx.infer_ctxt().build();
+ let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
+ let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+ match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {self_arg_ty}"),
+ }
};
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
@@ -1300,114 +1340,114 @@ fn compare_generic_param_kinds<'tcx>(
Ok(())
}
-pub(crate) fn compare_const_impl<'tcx>(
+/// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead
+pub(crate) fn raw_compare_const_impl<'tcx>(
tcx: TyCtxt<'tcx>,
- impl_c: &ty::AssocItem,
- impl_c_span: Span,
- trait_c: &ty::AssocItem,
- impl_trait_ref: ty::TraitRef<'tcx>,
-) {
+ (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
+) -> Result<(), ErrorGuaranteed> {
+ let impl_const_item = tcx.associated_item(impl_const_item_def);
+ let trait_const_item = tcx.associated_item(trait_const_item_def);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap();
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
- tcx.infer_ctxt().enter(|infcx| {
- let param_env = tcx.param_env(impl_c.def_id);
- let ocx = ObligationCtxt::new(&infcx);
-
- // The below is for the most part highly similar to the procedure
- // for methods above. It is simpler in many respects, especially
- // because we shouldn't really have to deal with lifetimes or
- // predicates. In fact some of this should probably be put into
- // shared functions because of DRY violations...
- let trait_to_impl_substs = impl_trait_ref.substs;
-
- // Create a parameter environment that represents the implementation's
- // method.
- let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_c.def_id.expect_local());
-
- // Compute placeholder form of impl and trait const tys.
- let impl_ty = tcx.type_of(impl_c.def_id);
- let trait_ty = tcx.bound_type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
- let mut cause = ObligationCause::new(
- impl_c_span,
- impl_c_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_c.def_id.expect_local(),
- trait_item_def_id: trait_c.def_id,
- kind: impl_c.kind,
- },
- );
+ let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
- // There is no "body" here, so just pass dummy id.
- let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
+ let infcx = tcx.infer_ctxt().build();
+ let param_env = tcx.param_env(impl_const_item_def.to_def_id());
+ let ocx = ObligationCtxt::new(&infcx);
- debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+ // The below is for the most part highly similar to the procedure
+ // for methods above. It is simpler in many respects, especially
+ // because we shouldn't really have to deal with lifetimes or
+ // predicates. In fact some of this should probably be put into
+ // shared functions because of DRY violations...
+ let trait_to_impl_substs = impl_trait_ref.substs;
- let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
+ // Create a parameter environment that represents the implementation's
+ // method.
+ let impl_c_hir_id = tcx.hir().local_def_id_to_hir_id(impl_const_item_def);
- debug!("compare_const_impl: trait_ty={:?}", trait_ty);
+ // Compute placeholder form of impl and trait const tys.
+ let impl_ty = tcx.type_of(impl_const_item_def.to_def_id());
+ let trait_ty = tcx.bound_type_of(trait_const_item_def).subst(tcx, trait_to_impl_substs);
+ let mut cause = ObligationCause::new(
+ impl_c_span,
+ impl_c_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_const_item_def,
+ trait_item_def_id: trait_const_item_def,
+ kind: impl_const_item.kind,
+ },
+ );
- let err = infcx
- .at(&cause, param_env)
- .sup(trait_ty, impl_ty)
- .map(|ok| ocx.register_infer_ok_obligations(ok));
+ // There is no "body" here, so just pass dummy id.
+ let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
- if let Err(terr) = err {
- debug!(
- "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
- impl_ty, trait_ty
- );
+ debug!("compare_const_impl: impl_ty={:?}", impl_ty);
- // Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
- ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
- _ => bug!("{:?} is not a impl const", impl_c),
- }
+ let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span,
- E0326,
- "implemented const `{}` has an incompatible type for trait",
- trait_c.name
- );
+ debug!("compare_const_impl: trait_ty={:?}", trait_ty);
- let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
- // Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_def_id).kind {
- TraitItemKind::Const(ref ty, _) => ty.span,
- _ => bug!("{:?} is not a trait const", trait_c),
- }
- });
+ let err = infcx
+ .at(&cause, param_env)
+ .sup(trait_ty, impl_ty)
+ .map(|ok| ocx.register_infer_ok_obligations(ok));
- infcx.note_type_err(
- &mut diag,
- &cause,
- trait_c_span.map(|span| (span, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_ty.into(),
- found: impl_ty.into(),
- })),
- terr,
- false,
- false,
- );
- diag.emit();
- }
+ if let Err(terr) = err {
+ debug!(
+ "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+ impl_ty, trait_ty
+ );
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- return;
+ // Locate the Span containing just the type of the offending impl
+ match tcx.hir().expect_impl_item(impl_const_item_def).kind {
+ ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
+ _ => bug!("{:?} is not a impl const", impl_const_item),
}
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- impl_c.def_id.expect_local(),
- &outlives_environment,
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ cause.span,
+ E0326,
+ "implemented const `{}` has an incompatible type for trait",
+ trait_const_item.name
);
- });
+
+ let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
+ // Add a label to the Span containing just the type of the const
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
+ TraitItemKind::Const(ref ty, _) => ty.span,
+ _ => bug!("{:?} is not a trait const", trait_const_item),
+ }
+ });
+
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_c_span.map(|span| (span, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_ty.into(),
+ found: impl_ty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+ return Err(diag.emit());
+ };
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+ }
+
+ // FIXME return `ErrorReported` if region obligations error?
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment);
+ Ok(())
}
pub(crate) fn compare_ty_impl<'tcx>(
@@ -1488,52 +1528,50 @@ fn compare_type_predicate_entailment<'tcx>(
hir::Constness::NotConst,
);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
- tcx.infer_ctxt().enter(|infcx| {
- let ocx = ObligationCtxt::new(&infcx);
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
- debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
+ debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
-
- assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
- for (span, predicate) in
- std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
- {
- let cause = ObligationCause::misc(span, impl_ty_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, cause, predicate);
-
- let cause = ObligationCause::new(
- span,
- impl_ty_hir_id,
- ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- kind: impl_ty.kind,
- },
- );
- ocx.register_obligations(obligations);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
- }
+ let mut selcx = traits::SelectionContext::new(&infcx);
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+ for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+ {
+ let cause = ObligationCause::misc(span, impl_ty_hir_id);
+ let traits::Normalized { value: predicate, obligations } =
+ traits::normalize(&mut selcx, param_env, cause, predicate);
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
+ let cause = ObligationCause::new(
+ span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ kind: impl_ty.kind,
+ },
);
+ ocx.register_obligations(obligations);
+ ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ }
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ );
- Ok(())
- })
+ Ok(())
}
/// Validate that `ProjectionCandidate`s created for this associated type will
@@ -1693,94 +1731,89 @@ pub fn check_type_bounds<'tcx>(
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
- tcx.infer_ctxt().enter(move |infcx| {
- let ocx = ObligationCtxt::new(&infcx);
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
- let assumed_wf_types =
- ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
+ let assumed_wf_types =
+ ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
- let mut selcx = traits::SelectionContext::new(&infcx);
- let normalize_cause = ObligationCause::new(
- impl_ty_span,
- impl_ty_hir_id,
- ObligationCauseCode::CheckAssociatedTypeBounds {
- impl_item_def_id: impl_ty.def_id.expect_local(),
- trait_item_def_id: trait_ty.def_id,
- },
- );
- let mk_cause = |span: Span| {
- let code = if span.is_dummy() {
- traits::ItemObligation(trait_ty.def_id)
- } else {
- traits::BindingObligation(trait_ty.def_id, span)
- };
- ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+ let mut selcx = traits::SelectionContext::new(&infcx);
+ let normalize_cause = ObligationCause::new(
+ impl_ty_span,
+ impl_ty_hir_id,
+ ObligationCauseCode::CheckAssociatedTypeBounds {
+ impl_item_def_id: impl_ty.def_id.expect_local(),
+ trait_item_def_id: trait_ty.def_id,
+ },
+ );
+ let mk_cause = |span: Span| {
+ let code = if span.is_dummy() {
+ traits::ItemObligation(trait_ty.def_id)
+ } else {
+ traits::BindingObligation(trait_ty.def_id, span)
};
+ ObligationCause::new(impl_ty_span, impl_ty_hir_id, code)
+ };
- let obligations = tcx
- .bound_explicit_item_bounds(trait_ty.def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .map(|(bound, span)| {
- debug!(?bound);
- // this is where opaque type is found
- let concrete_ty_bound = bound.subst(tcx, rebased_substs);
- debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
-
- traits::Obligation::new(mk_cause(span.0), param_env, concrete_ty_bound)
- })
- .collect();
- debug!("check_type_bounds: item_bounds={:?}", obligations);
-
- for mut obligation in util::elaborate_obligations(tcx, obligations) {
- let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
- &mut selcx,
- normalize_param_env,
- normalize_cause.clone(),
- obligation.predicate,
- );
- debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
- obligation.predicate = normalized_predicate;
+ let obligations = tcx
+ .bound_explicit_item_bounds(trait_ty.def_id)
+ .subst_iter_copied(tcx, rebased_substs)
+ .map(|(concrete_ty_bound, span)| {
+ debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
+ traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+ })
+ .collect();
+ debug!("check_type_bounds: item_bounds={:?}", obligations);
+
+ for mut obligation in util::elaborate_obligations(tcx, obligations) {
+ let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
+ &mut selcx,
+ normalize_param_env,
+ normalize_cause.clone(),
+ obligation.predicate,
+ );
+ debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
+ obligation.predicate = normalized_predicate;
- ocx.register_obligations(obligations);
- ocx.register_obligation(obligation);
- }
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
+ ocx.register_obligations(obligations);
+ ocx.register_obligation(obligation);
+ }
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
- // Finally, resolve all regions. This catches wily misuses of
- // lifetime parameters.
- let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
- let outlives_environment =
- OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters.
+ let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_hir_id, assumed_wf_types);
+ let outlives_environment =
+ OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(
- impl_ty.def_id.expect_local(),
- &outlives_environment,
- );
+ infcx.check_region_obligations_and_report_errors(
+ impl_ty.def_id.expect_local(),
+ &outlives_environment,
+ );
- let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- for (key, value) in constraints {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(
- value.hidden_type.span,
- tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
- ),
- tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
- value.hidden_type.ty,
- TypeError::Mismatch,
- )
- .emit();
- }
+ let constraints = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ for (key, value) in constraints {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(
+ value.hidden_type.span,
+ tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()),
+ ),
+ tcx.mk_opaque(key.def_id.to_def_id(), key.substs),
+ value.hidden_type.ty,
+ TypeError::Mismatch,
+ )
+ .emit();
+ }
- Ok(())
- })
+ Ok(())
}
fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index ab143c059..a74016e22 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,4 +1,4 @@
-// FIXME(@lcnr): Move this module out of `rustc_typeck`.
+// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
//
// We don't do any drop checking during hir typeck.
use crate::hir::def_id::{DefId, LocalDefId};
@@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
(ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
- // Since struct predicates cannot have ~const, project the impl predicate
- // onto one that ignores the constness. This is equivalent to saying that
- // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
- // in the impl.
- let non_const_a =
- ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
- relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
+ relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
@@ -198,7 +192,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
(
ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(b),
- ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
+ ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
(
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index c7425ff78..609095c9c 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -7,10 +7,10 @@ use crate::errors::{
};
use crate::require_same_types;
-use rustc_errors::struct_span_err;
+use hir::def_id::DefId;
+use rustc_errors::{struct_span_err, DiagnosticMessage};
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::spec::abi::Abi;
@@ -26,7 +26,7 @@ fn equate_intrinsic_type<'tcx>(
) {
let (own_counts, span) = match &it.kind {
hir::ForeignItemKind::Fn(.., generics) => {
- let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
+ let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts();
(own_counts, generics.span)
}
_ => {
@@ -57,13 +57,17 @@ fn equate_intrinsic_type<'tcx>(
{
let fty = tcx.mk_fn_ptr(sig);
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
- require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
+ require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
}
}
/// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
- match intrinsic {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety {
+ let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
+ true => hir::Unsafety::Normal,
+ false => hir::Unsafety::Unsafe,
+ };
+ let is_in_list = match tcx.item_name(intrinsic_id) {
// When adding a new intrinsic to this list,
// it's usually worth updating that intrinsic's documentation
// to note that it's safe to call, since
@@ -107,14 +111,26 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
| sym::variant_count
| sym::ptr_mask => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
+ };
+
+ if has_safe_attr != is_in_list {
+ tcx.sess.struct_span_err(
+ tcx.def_span(intrinsic_id),
+ DiagnosticMessage::Str(format!(
+ "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
+ tcx.item_name(intrinsic_id)
+ ))).emit();
}
+
+ is_in_list
}
/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
/// and in `library/core/src/intrinsics.rs`.
pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
- let intrinsic_name = tcx.item_name(it.def_id.to_def_id());
+ let intrinsic_id = it.owner_id.to_def_id();
+ let intrinsic_name = tcx.item_name(intrinsic_id);
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(
@@ -161,7 +177,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
};
(n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
} else {
- let unsafety = intrinsic_operation_unsafety(intrinsic_name);
+ let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, inputs, output) = match intrinsic_name {
sym::abort => (0, Vec::new(), tcx.types.never),
sym::unreachable => (0, Vec::new(), tcx.types.never),
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d8fe63dbf..17c4d0d48 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,104 +1,11 @@
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_index::vec::Idx;
-use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
use rustc_session::lint;
-use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_target::abi::{Pointer, VariantIdx};
+use rustc_span::{Symbol, DUMMY_SP};
use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
-use super::FnCtxt;
-
-/// If the type is `Option<T>`, it will return `T`, otherwise
-/// the type itself. Works on most `Option`-like types.
-fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
- let ty::Adt(def, substs) = *ty.kind() else { return ty };
-
- if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
- let data_idx;
-
- let one = VariantIdx::new(1);
- let zero = VariantIdx::new(0);
-
- if def.variant(zero).fields.is_empty() {
- data_idx = one;
- } else if def.variant(one).fields.is_empty() {
- data_idx = zero;
- } else {
- return ty;
- }
-
- if def.variant(data_idx).fields.len() == 1 {
- return def.variant(data_idx).fields[0].ty(tcx, substs);
- }
- }
-
- ty
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
- let convert = |ty: Ty<'tcx>| {
- let ty = self.resolve_vars_if_possible(ty);
- let ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- (SizeSkeleton::compute(ty, self.tcx, self.param_env), ty)
- };
- let (sk_from, from) = convert(from);
- let (sk_to, to) = convert(to);
-
- // Check for same size using the skeletons.
- if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
- if sk_from.same_size(sk_to) {
- return;
- }
-
- // Special-case transmuting from `typeof(function)` and
- // `Option<typeof(function)>` to present a clearer error.
- let from = unpack_option_like(self.tcx, from);
- if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&self.tcx) {
- struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type")
- .note(&format!("source type: {from}"))
- .note(&format!("target type: {to}"))
- .help("cast with `as` to a pointer instead")
- .emit();
- return;
- }
- }
-
- // Try to display a sensible error with as much information as possible.
- let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
- Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
- Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
- Err(LayoutError::Unknown(bad)) => {
- if bad == ty {
- "this type does not have a fixed size".to_owned()
- } else {
- format!("size can vary because of {bad}")
- }
- }
- Err(err) => err.to_string(),
- };
-
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0512,
- "cannot transmute between types of different sizes, \
- or dependently-sized types"
- );
- if from == to {
- err.note(&format!("`{from}` does not have a fixed size"));
- } else {
- err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
- .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
- }
- err.emit();
- }
-}
-
pub struct InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -126,7 +33,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
// Type still may have region variables, but `Sized` does not depend
// on those, so just erase them before querying.
- if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
+ if ty.is_sized(self.tcx, self.param_env) {
return true;
}
if let ty::Foreign(..) = ty.kind() {
@@ -146,7 +53,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
target_features: &FxHashSet<Symbol>,
) -> Option<InlineAsmType> {
let ty = (self.get_operand_ty)(expr);
- if ty.has_infer_types_or_consts() {
+ if ty.has_non_region_infer() {
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
}
let asm_ty_isize = match self.tcx.sess.target.pointer_width {
@@ -221,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
- if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) {
+ if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
let msg = "arguments for inline assembly must be copyable";
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(&format!("`{ty}` does not implement the Copy trait"));
@@ -328,17 +235,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
lint::builtin::ASM_SUB_REGISTER,
expr.hir_id,
spans,
+ "formatting may not be suitable for sub-register argument",
|lint| {
- let msg = "formatting may not be suitable for sub-register argument";
- let mut err = lint.build(msg);
- err.span_label(expr.span, "for this argument");
- err.help(&format!(
+ lint.span_label(expr.span, "for this argument");
+ lint.help(&format!(
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
));
- err.help(&format!(
+ lint.help(&format!(
"or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
));
- err.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index cfae63e4a..2e7b10257 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -62,195 +62,49 @@ a type parameter).
*/
-pub mod _match;
-mod autoderef;
-mod callee;
-pub mod cast;
mod check;
-mod closure;
-pub mod coercion;
mod compare_method;
-pub mod demand;
-mod diverges;
pub mod dropck;
-mod expectation;
-mod expr;
-mod fallback;
-mod fn_ctxt;
-mod gather_locals;
-mod generator_interior;
-mod inherited;
pub mod intrinsic;
-mod intrinsicck;
-pub mod method;
-mod op;
-mod pat;
-mod place_op;
+pub mod intrinsicck;
mod region;
-pub mod rvalue_scopes;
-mod upvar;
pub mod wfcheck;
-pub mod writeback;
-use check::{check_abi, check_fn, check_mod_item_types};
-pub use diverges::Diverges;
-pub use expectation::Expectation;
-pub use fn_ctxt::*;
-pub use inherited::{Inherited, InheritedBuilder};
+pub use check::check_abi;
-use crate::astconv::AstConv;
-use crate::check::gather_locals::GatherLocalsVisitor;
+use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{
- pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
-};
+use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
use rustc_hir as hir;
-use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt, UserType};
-use rustc_session::config;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::parse::feature_err;
-use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
-use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
-use self::coercion::DynamicCoerceMany;
use self::compare_method::collect_trait_impl_trait_tys;
use self::region::region_scope_tree;
-pub use self::Expectation::*;
-
-#[macro_export]
-macro_rules! type_error_struct {
- ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
- let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
-
- if $typ.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- err
- })
-}
-
-/// The type of a local binding, including the revealed type for anon types.
-#[derive(Copy, Clone, Debug)]
-pub struct LocalTy<'tcx> {
- decl_ty: Ty<'tcx>,
- revealed_ty: Ty<'tcx>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Needs {
- MutPlace,
- None,
-}
-
-impl Needs {
- fn maybe_mut_place(m: hir::Mutability) -> Self {
- match m {
- hir::Mutability::Mut => Needs::MutPlace,
- hir::Mutability::Not => Needs::None,
- }
- }
-}
-
-#[derive(Copy, Clone)]
-pub struct UnsafetyState {
- pub def: hir::HirId,
- pub unsafety: hir::Unsafety,
- from_fn: bool,
-}
-
-impl UnsafetyState {
- pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
- UnsafetyState { def, unsafety, from_fn: true }
- }
-
- pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
- use hir::BlockCheckMode;
- match self.unsafety {
- // If this unsafe, then if the outer function was already marked as
- // unsafe we shouldn't attribute the unsafe'ness to the block. This
- // way the block can be warned about instead of ignoring this
- // extraneous block (functions are never warned about).
- hir::Unsafety::Unsafe if self.from_fn => self,
-
- unsafety => {
- let (unsafety, def) = match blk.rules {
- BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
- BlockCheckMode::DefaultBlock => (unsafety, self.def),
- };
- UnsafetyState { def, unsafety, from_fn: false }
- }
- }
- }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum PlaceOp {
- Deref,
- Index,
-}
-
-pub struct BreakableCtxt<'tcx> {
- may_break: bool,
-
- // this is `null` for loops where break with a value is illegal,
- // such as `while`, `for`, and `while let`
- coerce: Option<DynamicCoerceMany<'tcx>>,
-}
-
-pub struct EnclosingBreakables<'tcx> {
- stack: Vec<BreakableCtxt<'tcx>>,
- by_id: HirIdMap<usize>,
-}
-
-impl<'tcx> EnclosingBreakables<'tcx> {
- fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
- self.opt_find_breakable(target_id).unwrap_or_else(|| {
- bug!("could not find enclosing breakable with id {}", target_id);
- })
- }
-
- fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
- match self.by_id.get(&target_id) {
- Some(ix) => Some(&mut self.stack[*ix]),
- None => None,
- }
- }
-}
pub fn provide(providers: &mut Providers) {
- method::provide(providers);
wfcheck::provide(providers);
*providers = Providers {
- typeck_item_bodies,
- typeck_const_arg,
- typeck,
- diagnostic_only_typeck,
- has_typeck_results,
adt_destructor,
- used_trait_imports,
check_mod_item_types,
region_scope_tree,
collect_trait_impl_trait_tys,
+ compare_assoc_const_impl_item_with_trait_item: compare_method::raw_compare_const_impl,
..*providers
};
}
@@ -259,255 +113,6 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
tcx.calculate_dtor(def_id, dropck::check_drop_impl)
}
-/// If this `DefId` is a "primary tables entry", returns
-/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
-///
-/// If this function returns `Some`, then `typeck_results(def_id)` will
-/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
-/// may not succeed. In some cases where this function returns `None`
-/// (notably closures), `typeck_results(def_id)` would wind up
-/// redirecting to the owning function.
-fn primary_body_of(
- tcx: TyCtxt<'_>,
- id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
- match tcx.hir().get(id) {
- Node::Item(item) => match item.kind {
- hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
- Some((body, Some(ty), None))
- }
- hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
- _ => None,
- },
- Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- Some((body, None, Some(sig)))
- }
- _ => None,
- },
- Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
- hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
- _ => None,
- },
- Node::AnonConst(constant) => Some((constant.body, None, None)),
- _ => None,
- }
-}
-
-fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- // Closures' typeck results come from their outermost function,
- // as they are part of the same "inference environment".
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
- if typeck_root_def_id != def_id {
- return tcx.has_typeck_results(typeck_root_def_id);
- }
-
- if let Some(def_id) = def_id.as_local() {
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- primary_body_of(tcx, id).is_some()
- } else {
- false
- }
-}
-
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
- &*tcx.typeck(def_id).used_trait_imports
-}
-
-fn typeck_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
- let fallback = move || tcx.type_of(param_did);
- typeck_with_fallback(tcx, did, fallback)
-}
-
-fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- if let Some(param_did) = tcx.opt_const_param_of(def_id) {
- tcx.typeck_const_arg((def_id, param_did))
- } else {
- let fallback = move || tcx.type_of(def_id.to_def_id());
- typeck_with_fallback(tcx, def_id, fallback)
- }
-}
-
-/// Used only to get `TypeckResults` for type inference during error recovery.
-/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
-fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- let fallback = move || {
- let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
- tcx.ty_error_with_message(span, "diagnostic only typeck table used")
- };
- typeck_with_fallback(tcx, def_id, fallback)
-}
-
-fn typeck_with_fallback<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
- fallback: impl Fn() -> Ty<'tcx> + 'tcx,
-) -> &'tcx ty::TypeckResults<'tcx> {
- // Closures' typeck results come from their outermost function,
- // as they are part of the same "inference environment".
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
- if typeck_root_def_id != def_id {
- return tcx.typeck(typeck_root_def_id);
- }
-
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- let span = tcx.hir().span(id);
-
- // Figure out what primary body this item has.
- let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
- span_bug!(span, "can't type-check body of {:?}", def_id);
- });
- let body = tcx.hir().body(body_id);
-
- let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
- let param_env = tcx.param_env(def_id);
- let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
- let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
- } else {
- tcx.fn_sig(def_id)
- };
-
- check_abi(tcx, id, span, fn_sig.abi());
-
- // Compute the function signature from point of view of inside the fn.
- let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- let fn_sig = inh.normalize_associated_types_in(
- body.value.span,
- body_id.hir_id,
- param_env,
- fn_sig,
- );
- check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
- } else {
- let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
- let expected_type = body_ty
- .and_then(|ty| match ty.kind {
- hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
- _ => None,
- })
- .unwrap_or_else(|| match tcx.hir().get(id) {
- Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::ConstBlock(ref anon_const),
- ..
- }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- }),
- Node::Ty(&hir::Ty {
- kind: hir::TyKind::Typeof(ref anon_const), ..
- }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- }),
- Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
- | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
- let operand_ty = asm
- .operands
- .iter()
- .filter_map(|(op, _op_sp)| match op {
- hir::InlineAsmOperand::Const { anon_const }
- if anon_const.hir_id == id =>
- {
- // Inline assembly constants must be integers.
- Some(fcx.next_int_var())
- }
- hir::InlineAsmOperand::SymFn { anon_const }
- if anon_const.hir_id == id =>
- {
- Some(fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span,
- }))
- }
- _ => None,
- })
- .next();
- operand_ty.unwrap_or_else(fallback)
- }
- _ => fallback(),
- },
- _ => fallback(),
- });
-
- let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
- fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
- // Gather locals in statics (because of block expressions).
- GatherLocalsVisitor::new(&fcx).visit_body(body);
-
- fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
-
- fcx.write_ty(id, expected_type);
-
- fcx
- };
-
- let fallback_has_occurred = fcx.type_inference_fallback();
-
- // Even though coercion casts provide type hints, we check casts after fallback for
- // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
- fcx.check_casts();
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
- // Closure and generator analysis may run after fallback
- // because they don't constrain other type variables.
- fcx.closure_analyze(body);
- assert!(fcx.deferred_call_resolutions.borrow().is_empty());
- // Before the generator analysis, temporary scopes shall be marked to provide more
- // precise information on types to be captured.
- fcx.resolve_rvalue_scopes(def_id.to_def_id());
- fcx.resolve_generator_interiors(def_id.to_def_id());
-
- for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
- let ty = fcx.normalize_ty(span, ty);
- fcx.require_type_is_sized(ty, span, code);
- }
-
- fcx.select_all_obligations_or_error();
-
- if !fcx.infcx.is_tainted_by_errors() {
- fcx.check_transmutes();
- }
-
- fcx.check_asms();
-
- fcx.infcx.skip_region_resolution();
-
- fcx.resolve_type_vars_in_body(body)
- });
-
- // Consistency check our TypeckResults instance can hold all ItemLocalIds
- // it will need to hold.
- assert_eq!(typeck_results.hir_owner, id.owner);
-
- typeck_results
-}
-
-/// When `check_fn` is invoked on a generator (i.e., a body that
-/// includes yield), it returns back some information about the yield
-/// points.
-struct GeneratorTypes<'tcx> {
- /// Type of generator argument / values returned by `yield`.
- resume_ty: Ty<'tcx>,
-
- /// Type of value that is yielded.
- yield_ty: Ty<'tcx>,
-
- /// Types that are captured (see `GeneratorInterior` for more).
- interior: Ty<'tcx>,
-
- /// Indicates if the generator is movable or static (immovable).
- movability: hir::Movability,
-}
-
/// Given a `DefId` for an opaque type in return position, find its parent item's return
/// expressions.
fn get_owner_return_paths<'tcx>(
@@ -515,7 +120,7 @@ fn get_owner_return_paths<'tcx>(
def_id: LocalDefId,
) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
let body = tcx.hir().body(body_id);
let mut visitor = ReturnsVisitor::default();
@@ -524,9 +129,10 @@ fn get_owner_return_paths<'tcx>(
})
}
-// Forbid defining intrinsics in Rust code,
-// as they must always be defined by the compiler.
-fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
+/// Forbid defining intrinsics in Rust code,
+/// as they must always be defined by the compiler.
+// FIXME: Move this to a more appropriate place.
+pub fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
}
@@ -820,6 +426,17 @@ fn fn_sig_suggestion<'tcx>(
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
}
+pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+ Some(match ty.kind() {
+ ty::Bool => "true",
+ ty::Char => "'a'",
+ ty::Int(_) | ty::Uint(_) => "42",
+ ty::Float(_) => "3.14159",
+ ty::Error(_) | ty::Never => return None,
+ _ => "value",
+ })
+}
+
/// Return placeholder code for the given associated item.
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
/// structured suggestion.
@@ -841,7 +458,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id);
- let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
+ let val = ty_kind_suggestion(ty).unwrap_or("value");
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
@@ -892,76 +509,7 @@ fn bad_non_zero_sized_fields<'tcx>(
err.emit();
}
-fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
- struct_span_err!(
- tcx.sess,
- span,
- E0533,
- "expected unit struct, unit variant or constant, found {} `{}`",
- res.descr(),
- rustc_hir_pretty::qpath_to_string(qpath),
- )
- .emit();
-}
-
-/// Controls whether the arguments are tupled. This is used for the call
-/// operator.
-///
-/// Tupling means that all call-side arguments are packed into a tuple and
-/// passed as a single parameter. For example, if tupling is enabled, this
-/// function:
-/// ```
-/// fn f(x: (isize, isize)) {}
-/// ```
-/// Can be called as:
-/// ```ignore UNSOLVED (can this be done in user code?)
-/// # fn f(x: (isize, isize)) {}
-/// f(1, 2);
-/// ```
-/// Instead of:
-/// ```
-/// # fn f(x: (isize, isize)) {}
-/// f((1, 2));
-/// ```
-#[derive(Clone, Eq, PartialEq)]
-enum TupleArgumentsFlag {
- DontTupleArguments,
- TupleArguments,
-}
-
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
- tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn fatally_break_rust(sess: &Session) {
- let handler = sess.diagnostic();
- handler.span_bug_no_panic(
- MultiSpan::new(),
- "It looks like you're trying to break rust; would you like some ICE?",
- );
- handler.note_without_error("the compiler expectedly panicked. this is a feature.");
- handler.note_without_error(
- "we would appreciate a joke overview: \
- https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
- );
- handler.note_without_error(&format!(
- "rustc {} running on {}",
- option_env!("CFG_VERSION").unwrap_or("unknown_version"),
- config::host_triple(),
- ));
-}
-
-fn potentially_plural_count(count: usize, word: &str) -> String {
+// FIXME: Consider moving this method to a more fitting place.
+pub fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count))
}
-
-fn has_expected_num_generic_args<'tcx>(
- tcx: TyCtxt<'tcx>,
- trait_did: Option<DefId>,
- expected: usize,
-) -> bool {
- trait_did.map_or(true, |trait_did| {
- let generics = tcx.generics_of(trait_did);
- generics.count() == expected + if generics.has_self { 1 } else { 0 }
- })
-}
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b89db79be..ff32329e4 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -252,9 +252,13 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
) => {
// For shortcircuiting operators, mark the RHS as a terminating
// scope since it only executes conditionally.
- terminating(r.hir_id.local_id);
- }
+ // `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
+ // should live beyond the immediate expression
+ if !matches!(r.kind, hir::ExprKind::Let(_)) {
+ terminating(r.hir_id.local_id);
+ }
+ }
hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
terminating(then.hir_id.local_id);
terminating(otherwise.hir_id.local_id);
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 27b3da8ab..a23575004 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -12,17 +12,17 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
+use rustc_middle::ty::{GenericArgKind, InternalSubsts};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::autoderef::Autoderef;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
@@ -91,32 +91,31 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
{
let param_env = tcx.param_env(body_def_id);
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
- let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
+ let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
- let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
+ let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
- if !tcx.features().trivial_bounds {
- wfcx.check_false_global_bounds()
- }
- f(&mut wfcx);
- let errors = wfcx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- return;
- }
+ if !tcx.features().trivial_bounds {
+ wfcx.check_false_global_bounds()
+ }
+ f(&mut wfcx);
+ let errors = wfcx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return;
+ }
- let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
- let outlives_environment =
- OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+ let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
+ let outlives_environment =
+ OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
- })
+ infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
}
-fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
let node = tcx.hir().expect_owner(def_id);
match node {
hir::OwnerNode::Crate(_) => {}
@@ -148,10 +147,10 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
/// the types first.
#[instrument(skip(tcx), level = "debug")]
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
@@ -175,7 +174,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
// for `T`
hir::ItemKind::Impl(ref impl_) => {
let is_auto = tcx
- .impl_trait_ref(item.def_id)
+ .impl_trait_ref(def_id)
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
@@ -211,13 +210,13 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
}
hir::ItemKind::Fn(ref sig, ..) => {
- check_item_fn(tcx, item.def_id, item.ident, item.span, sig.decl);
+ check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
}
hir::ItemKind::Static(ty, ..) => {
- check_item_type(tcx, item.def_id, ty.span, false);
+ check_item_type(tcx, def_id, ty.span, false);
}
hir::ItemKind::Const(ty, ..) => {
- check_item_type(tcx, item.def_id, ty.span, false);
+ check_item_type(tcx, def_id, ty.span, false);
}
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
@@ -247,24 +246,24 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
- let def_id = item.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
match item.kind {
hir::ForeignItemKind::Fn(decl, ..) => {
- check_item_fn(tcx, item.def_id, item.ident, item.span, decl)
+ check_item_fn(tcx, def_id, item.ident, item.span, decl)
}
- hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, item.def_id, ty.span, true),
+ hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
hir::ForeignItemKind::Type => (),
}
}
fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
- let def_id = trait_item.def_id;
+ let def_id = trait_item.owner_id.def_id;
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
@@ -272,11 +271,11 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
_ => (None, trait_item.span),
};
check_object_unsafe_self_trait_by_name(tcx, trait_item);
- check_associated_item(tcx, trait_item.def_id, span, method_sig);
+ check_associated_item(tcx, def_id, span, method_sig);
let encl_trait_def_id = tcx.local_parent(def_id);
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
- let encl_trait_def_id = encl_trait.def_id.to_def_id();
+ let encl_trait_def_id = encl_trait.owner_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
} else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
@@ -349,7 +348,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
loop {
let mut should_continue = false;
for gat_item in associated_items {
- let gat_def_id = gat_item.id.def_id;
+ let gat_def_id = gat_item.id.owner_id;
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no substs, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
@@ -366,7 +365,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
for item in associated_items {
- let item_def_id = item.id.def_id;
+ let item_def_id = item.id.owner_id;
// Skip our own GAT, since it does not constrain itself at all.
if item_def_id == gat_def_id {
continue;
@@ -393,7 +392,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
// We also assume that all of the function signature's parameter types
// are well formed.
&sig.inputs().iter().copied().collect(),
- gat_def_id,
+ gat_def_id.def_id,
gat_generics,
)
}
@@ -416,7 +415,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.copied()
.collect::<Vec<_>>(),
&FxHashSet::default(),
- gat_def_id,
+ gat_def_id.def_id,
gat_generics,
)
}
@@ -456,7 +455,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
}
for (gat_def_id, required_bounds) in required_bounds_by_item {
- let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+ let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id);
debug!(?required_bounds);
let param_env = tcx.param_env(gat_def_id);
let gat_hir = gat_item_hir.hir_id();
@@ -699,29 +698,32 @@ fn resolve_regions_with_wf_tys<'tcx>(
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
wf_tys: &FxHashSet<Ty<'tcx>>,
- add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'a, 'tcx>, &'a RegionBoundPairs<'tcx>),
+ add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
// region constraints get added and solved there and we need to test each
// call individually.
- tcx.infer_ctxt().enter(|infcx| {
- let outlives_environment = OutlivesEnvironment::with_bounds(
- param_env,
- Some(&infcx),
- infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
- );
- let region_bound_pairs = outlives_environment.region_bound_pairs();
+ let infcx = tcx.infer_ctxt().build();
+ let outlives_environment = OutlivesEnvironment::with_bounds(
+ param_env,
+ Some(&infcx),
+ infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
+ );
+ let region_bound_pairs = outlives_environment.region_bound_pairs();
- add_constraints(&infcx, region_bound_pairs);
+ add_constraints(&infcx, region_bound_pairs);
- let errors = infcx.resolve_regions(&outlives_environment);
+ infcx.process_registered_region_obligations(
+ outlives_environment.region_bound_pairs(),
+ param_env,
+ );
+ let errors = infcx.resolve_regions(&outlives_environment);
- debug!(?errors, "errors");
+ debug!(?errors, "errors");
- // If we were able to prove that the type outlives the region without
- // an error, it must be because of the implied or explicit bounds...
- errors.is_empty()
- })
+ // If we were able to prove that the type outlives the region without
+ // an error, it must be because of the implied or explicit bounds...
+ errors.is_empty()
}
/// TypeVisitor that looks for uses of GATs like
@@ -786,9 +788,9 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
/// When this is done, suggest using `Self` instead.
fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
let (trait_name, trait_def_id) =
- match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id())) {
+ match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) {
hir::Node::Item(item) => match item.kind {
- hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+ hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
_ => return,
},
_ => return,
@@ -796,18 +798,18 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
let mut trait_should_be_self = vec![];
match &item.kind {
hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
- if could_be_self(trait_def_id, ty) =>
+ if could_be_self(trait_def_id.def_id, ty) =>
{
trait_should_be_self.push(ty.span)
}
hir::TraitItemKind::Fn(sig, _) => {
for ty in sig.decl.inputs {
- if could_be_self(trait_def_id, ty) {
+ if could_be_self(trait_def_id.def_id, ty) {
trait_should_be_self.push(ty.span);
}
}
match sig.decl.output {
- hir::FnRetTy::Return(ty) if could_be_self(trait_def_id, ty) => {
+ hir::FnRetTy::Return(ty) if could_be_self(trait_def_id.def_id, ty) => {
trait_should_be_self.push(ty.span);
}
_ => {}
@@ -836,16 +838,14 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
}
fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
- let def_id = impl_item.def_id;
-
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
- hir::ImplItemKind::TyAlias(ty) if ty.span != DUMMY_SP => (None, ty.span),
+ hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
_ => (None, impl_item.span),
};
- check_associated_item(tcx, def_id, span, method_sig);
+ check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
}
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -1045,9 +1045,11 @@ fn check_type_defn<'tcx, F>(
) where
F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
{
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+ let _ = tcx.representability(item.owner_id.def_id);
+
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
let variants = lookup_fields(wfcx);
- let packed = tcx.adt_def(item.def_id).repr().packed();
+ let packed = tcx.adt_def(item.owner_id).repr().packed();
for variant in &variants {
// All field types must be well-formed.
@@ -1071,7 +1073,7 @@ fn check_type_defn<'tcx, F>(
// Just treat unresolved type expression as if it needs drop.
true
} else {
- ty.needs_drop(tcx, tcx.param_env(item.def_id))
+ ty.needs_drop(tcx, tcx.param_env(item.owner_id))
}
}
};
@@ -1103,8 +1105,6 @@ fn check_type_defn<'tcx, F>(
// Explicit `enum` discriminant values must const-evaluate successfully.
if let Some(discr_def_id) = variant.explicit_discr {
- let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
-
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
@@ -1113,28 +1113,28 @@ fn check_type_defn<'tcx, F>(
wfcx.register_obligation(traits::Obligation::new(
cause,
wfcx.param_env,
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
- ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
- discr_substs,
- )))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
+ ty::Const::from_anon_const(tcx, discr_def_id),
+ ))
.to_predicate(tcx),
));
}
}
- check_where_clauses(wfcx, item.span, item.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
#[instrument(skip(tcx, item))]
fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
- debug!(?item.def_id);
+ debug!(?item.owner_id);
- let trait_def = tcx.trait_def(item.def_id);
+ let def_id = item.owner_id.def_id;
+ let trait_def = tcx.trait_def(def_id);
if trait_def.is_marker
|| matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
{
- for associated_def_id in &*tcx.associated_item_def_ids(item.def_id) {
+ for associated_def_id in &*tcx.associated_item_def_ids(def_id) {
struct_span_err!(
tcx.sess,
tcx.def_span(*associated_def_id),
@@ -1145,8 +1145,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
}
}
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
- check_where_clauses(wfcx, item.span, item.def_id)
+ enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
+ check_where_clauses(wfcx, item.span, def_id)
});
// Only check traits, don't check trait aliases
@@ -1240,13 +1240,13 @@ fn check_impl<'tcx>(
ast_trait_ref: &Option<hir::TraitRef<'_>>,
constness: hir::Constness,
) {
- enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
match *ast_trait_ref {
Some(ref ast_trait_ref) => {
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
- let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
let trait_pred = ty::TraitPredicate {
trait_ref,
@@ -1268,21 +1268,21 @@ fn check_impl<'tcx>(
wfcx.register_obligations(obligations);
}
None => {
- let self_ty = tcx.type_of(item.def_id);
+ let self_ty = tcx.type_of(item.owner_id);
let self_ty = wfcx.normalize(
item.span,
- Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty,
);
wfcx.register_wf_obligation(
ast_self_ty.span,
- Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
+ Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty.into(),
);
}
}
- check_where_clauses(wfcx, item.span, item.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
@@ -1427,9 +1427,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
- if substituted_pred.has_param_types_or_consts()
- || param_count.params.len() > 1
- || has_region
+ if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region
{
None
} else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
@@ -1678,7 +1676,7 @@ fn receiver_is_valid<'tcx>(
// `self: Self` is always valid.
if can_eq_self(receiver_ty) {
if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
- infcx.report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
+ infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
}
return true;
}
@@ -1710,7 +1708,10 @@ fn receiver_is_valid<'tcx>(
if let Err(err) =
wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
{
- infcx.report_mismatched_types(&cause, self_ty, potential_self_ty, err).emit();
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(&cause, self_ty, potential_self_ty, err)
+ .emit();
}
break;
@@ -1777,14 +1778,14 @@ fn check_variances_for_type_defn<'tcx>(
item: &hir::Item<'tcx>,
hir_generics: &hir::Generics<'_>,
) {
- let ty = tcx.type_of(item.def_id);
+ let ty = tcx.type_of(item.owner_id);
if tcx.has_error_field(ty) {
return;
}
- let ty_predicates = tcx.predicates_of(item.def_id);
+ let ty_predicates = tcx.predicates_of(item.owner_id);
assert_eq!(ty_predicates.parent, None);
- let variances = tcx.variances_of(item.def_id);
+ let variances = tcx.variances_of(item.owner_id);
let mut constrained_parameters: FxHashSet<_> = variances
.iter()
@@ -1797,7 +1798,7 @@ fn check_variances_for_type_defn<'tcx>(
// Lazily calculated because it is only needed in case of an error.
let explicitly_bounded_params = LazyCell::new(|| {
- let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+ let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id());
hir_generics
.predicates
.iter()
@@ -1918,10 +1919,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
let items = tcx.hir_module_items(module);
- items.par_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id));
+ items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
}
///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 1d23ed929..d0c317334 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -1,5 +1,6 @@
use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unord::UnordSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -8,12 +9,12 @@ use rustc_session::lint;
use rustc_span::{Span, Symbol};
pub fn check_crate(tcx: TyCtxt<'_>) {
- let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default();
+ let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
for item_def_id in tcx.hir().body_owners() {
let imports = tcx.used_trait_imports(item_def_id);
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
- used_trait_imports.extend(imports.iter());
+ used_trait_imports.extend(imports.items().copied());
}
for &id in tcx.maybe_unused_trait_imports(()) {
@@ -29,14 +30,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
continue;
}
let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
- tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
- let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
- format!("unused import: `{}`", snippet)
- } else {
- "unused import".to_owned()
- };
- lint.build(&msg).emit();
- });
+ let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+ format!("unused import: `{}`", snippet)
+ } else {
+ "unused import".to_owned()
+ };
+ tcx.struct_span_lint_hir(
+ lint::builtin::UNUSED_IMPORTS,
+ item.hir_id(),
+ path.span,
+ msg,
+ |lint| lint,
+ );
}
unused_crates_lint(tcx);
@@ -85,11 +90,11 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
let mut crates_to_lint = vec![];
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::ExternCrate) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
let item = tcx.hir().item(id);
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
crates_to_lint.push(ExternCrateToLint {
- def_id: item.def_id.to_def_id(),
+ def_id: item.owner_id.to_def_id(),
span: item.span,
orig_name,
warn_if_unused: !item.ident.as_str().starts_with('_'),
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
new file mode 100644
index 000000000..b6c91d425
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -0,0 +1,572 @@
+//! Check properties that are required by built-in traits and set
+//! up data structures required by type-checking/codegen.
+
+use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
+use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::ItemKind;
+use rustc_infer::infer;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
+use rustc_trait_selection::traits::predicate_for_trait_def;
+use rustc_trait_selection::traits::{self, ObligationCause};
+use std::collections::BTreeMap;
+
+pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
+ let lang_items = tcx.lang_items();
+ Checker { tcx, trait_def_id }
+ .check(lang_items.drop_trait(), visit_implementation_of_drop)
+ .check(lang_items.copy_trait(), visit_implementation_of_copy)
+ .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
+ .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
+}
+
+struct Checker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+}
+
+impl<'tcx> Checker<'tcx> {
+ fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+ where
+ F: FnMut(TyCtxt<'tcx>, LocalDefId),
+ {
+ if Some(self.trait_def_id) == trait_def_id {
+ for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
+ f(self.tcx, impl_def_id);
+ }
+ }
+ self
+ }
+}
+
+fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ // Destructors only work on local ADT types.
+ match tcx.type_of(impl_did).kind() {
+ ty::Adt(def, _) if def.did().is_local() => return,
+ ty::Error(_) => return,
+ _ => {}
+ }
+
+ let sp = match tcx.hir().expect_item(impl_did).kind {
+ ItemKind::Impl(ref impl_) => impl_.self_ty.span,
+ _ => bug!("expected Drop impl item"),
+ };
+
+ tcx.sess.emit_err(DropImplOnWrongItem { span: sp });
+}
+
+fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
+
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+
+ let self_type = tcx.type_of(impl_did);
+ debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
+
+ let param_env = tcx.param_env(impl_did);
+ assert!(!self_type.has_escaping_bound_vars());
+
+ debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
+
+ let span = match tcx.hir().expect_item(impl_did).kind {
+ ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return,
+ ItemKind::Impl(impl_) => impl_.self_ty.span,
+ _ => bug!("expected Copy impl item"),
+ };
+
+ let cause = traits::ObligationCause::misc(span, impl_hir_id);
+ match can_type_implement_copy(tcx, param_env, self_type, cause) {
+ Ok(()) => {}
+ Err(CopyImplementationError::InfrigingFields(fields)) => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0204,
+ "the trait `Copy` may not be implemented for this type"
+ );
+
+ // We'll try to suggest constraining type parameters to fulfill the requirements of
+ // their `Copy` implementation.
+ let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+ let mut bounds = vec![];
+
+ for (field, ty) in fields {
+ let field_span = tcx.def_span(field.did);
+ let field_ty_span = match tcx.hir().get_if_local(field.did) {
+ Some(hir::Node::Field(field_def)) => field_def.ty.span,
+ _ => field_span,
+ };
+ err.span_label(field_span, "this field does not implement `Copy`");
+ // Spin up a new FulfillmentContext, so we can get the _precise_ reason
+ // why this field does not implement Copy. This is useful because sometimes
+ // it is not immediately clear why Copy is not implemented for a field, since
+ // all we point at is the field itself.
+ let infcx = tcx.infer_ctxt().ignoring_regions().build();
+ for error in traits::fully_solve_bound(
+ &infcx,
+ traits::ObligationCause::dummy_with_span(field_ty_span),
+ param_env,
+ ty,
+ tcx.lang_items().copy_trait().unwrap(),
+ ) {
+ let error_predicate = error.obligation.predicate;
+ // Only note if it's not the root obligation, otherwise it's trivial and
+ // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+ // FIXME: This error could be more descriptive, especially if the error_predicate
+ // contains a foreign type or if it's a deeply nested type...
+ if error_predicate != error.root_obligation.predicate {
+ errors
+ .entry((ty.to_string(), error_predicate.to_string()))
+ .or_default()
+ .push(error.obligation.cause.span);
+ }
+ if let ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ ..
+ }) = error_predicate.kind().skip_binder()
+ {
+ let ty = trait_ref.self_ty();
+ if let ty::Param(_) = ty.kind() {
+ bounds.push((
+ format!("{ty}"),
+ trait_ref.print_only_trait_path().to_string(),
+ Some(trait_ref.def_id),
+ ));
+ }
+ }
+ }
+ }
+ for ((ty, error_predicate), spans) in errors {
+ let span: MultiSpan = spans.into();
+ err.span_note(
+ span,
+ &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
+ );
+ }
+ suggest_constraining_type_params(
+ tcx,
+ tcx.hir().get_generics(impl_did).expect("impls always have generics"),
+ &mut err,
+ bounds.iter().map(|(param, constraint, def_id)| {
+ (param.as_str(), constraint.as_str(), *def_id)
+ }),
+ );
+ err.emit();
+ }
+ Err(CopyImplementationError::NotAnAdt) => {
+ tcx.sess.emit_err(CopyImplOnNonAdt { span });
+ }
+ Err(CopyImplementationError::HasDestructor) => {
+ tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
+ }
+ }
+}
+
+fn visit_implementation_of_coerce_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
+
+ // Just compute this for the side-effects, in particular reporting
+ // errors; other parts of the code may demand it for the info of
+ // course.
+ let span = tcx.def_span(impl_did);
+ tcx.at(span).coerce_unsized_info(impl_did);
+}
+
+fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) {
+ debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
+
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+ let span = tcx.hir().span(impl_hir_id);
+
+ let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
+
+ let source = tcx.type_of(impl_did);
+ assert!(!source.has_escaping_bound_vars());
+ let target = {
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
+
+ trait_ref.substs.type_at(1)
+ };
+
+ debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
+
+ let param_env = tcx.param_env(impl_did);
+
+ let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
+
+ let infcx = tcx.infer_ctxt().build();
+ let cause = ObligationCause::misc(span, impl_hir_id);
+
+ use rustc_type_ir::sty::TyKind::*;
+ match (source.kind(), target.kind()) {
+ (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
+ if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
+ (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
+ (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() =>
+ {
+ if def_a != def_b {
+ let source_path = tcx.def_path_str(def_a.did());
+ let target_path = tcx.def_path_str(def_b.did());
+
+ create_err(&format!(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected `{}`, found `{}`",
+ source_path, target_path,
+ ))
+ .emit();
+
+ return;
+ }
+
+ if def_a.repr().c() || def_a.repr().packed() {
+ create_err(
+ "structs implementing `DispatchFromDyn` may not have \
+ `#[repr(packed)]` or `#[repr(C)]`",
+ )
+ .emit();
+ }
+
+ let fields = &def_a.non_enum_variant().fields;
+
+ let coerced_fields = fields
+ .iter()
+ .filter(|field| {
+ let ty_a = field.ty(tcx, substs_a);
+ let ty_b = field.ty(tcx, substs_b);
+
+ if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
+ if layout.is_zst() && layout.align.abi.bytes() == 1 {
+ // ignore ZST fields with alignment of 1 byte
+ return false;
+ }
+ }
+
+ if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
+ if ok.obligations.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for structs containing the field being coerced, \
+ ZST fields with 1 byte alignment, and nothing else",
+ )
+ .note(&format!(
+ "extra field `{}` of type `{}` is not allowed",
+ field.name, ty_a,
+ ))
+ .emit();
+
+ return false;
+ }
+ }
+
+ return true;
+ })
+ .collect::<Vec<_>>();
+
+ if coerced_fields.is_empty() {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced, none found",
+ )
+ .emit();
+ } else if coerced_fields.len() > 1 {
+ create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
+ .note(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures with a single field \
+ being coerced",
+ )
+ .note(&format!(
+ "currently, {} fields need coercions: {}",
+ coerced_fields.len(),
+ coerced_fields
+ .iter()
+ .map(|field| {
+ format!(
+ "`{}` (`{}` to `{}`)",
+ field.name,
+ field.ty(tcx, substs_a),
+ field.ty(tcx, substs_b),
+ )
+ })
+ .collect::<Vec<_>>()
+ .join(", ")
+ ))
+ .emit();
+ } else {
+ let errors = traits::fully_solve_obligations(
+ &infcx,
+ coerced_fields.into_iter().map(|field| {
+ predicate_for_trait_def(
+ tcx,
+ param_env,
+ cause.clone(),
+ dispatch_from_dyn_trait,
+ 0,
+ field.ty(tcx, substs_a),
+ &[field.ty(tcx, substs_b).into()],
+ )
+ }),
+ );
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+
+ // Finally, resolve all regions.
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+ }
+ }
+ _ => {
+ create_err(
+ "the trait `DispatchFromDyn` may only be implemented \
+ for a coercion between structures",
+ )
+ .emit();
+ }
+ }
+}
+
+pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
+ debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
+
+ // this provider should only get invoked for local def-ids
+ let impl_did = impl_did.expect_local();
+ let span = tcx.def_span(impl_did);
+
+ let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
+
+ let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
+ tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string()));
+ });
+
+ let source = tcx.type_of(impl_did);
+ let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
+ assert_eq!(trait_ref.def_id, coerce_unsized_trait);
+ let target = trait_ref.substs.type_at(1);
+ debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
+
+ let param_env = tcx.param_env(impl_did);
+ assert!(!source.has_escaping_bound_vars());
+
+ let err_info = CoerceUnsizedInfo { custom_kind: None };
+
+ debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
+
+ let infcx = tcx.infer_ctxt().build();
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
+ let cause = ObligationCause::misc(span, impl_hir_id);
+ let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
+ mt_b: ty::TypeAndMut<'tcx>,
+ mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
+ if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &cause,
+ mk_ptr(mt_b.ty),
+ target,
+ ty::error::TypeError::Mutability,
+ )
+ .emit();
+ }
+ (mt_a.ty, mt_b.ty, unsize_trait, None)
+ };
+ let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
+ (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
+ infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
+ let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+ let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+ }
+
+ (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
+ let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
+ check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+ }
+
+ (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)),
+
+ (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
+ if def_a.is_struct() && def_b.is_struct() =>
+ {
+ if def_a != def_b {
+ let source_path = tcx.def_path_str(def_a.did());
+ let target_path = tcx.def_path_str(def_b.did());
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0377,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with the same \
+ definition; expected `{}`, found `{}`",
+ source_path,
+ target_path
+ )
+ .emit();
+ return err_info;
+ }
+
+ // Here we are considering a case of converting
+ // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
+ // which acts like a pointer to `U`, but carries along some extra data of type `T`:
+ //
+ // struct Foo<T, U> {
+ // extra: T,
+ // ptr: *mut U,
+ // }
+ //
+ // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
+ // to `Foo<T, [i32]>`. That impl would look like:
+ //
+ // impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
+ //
+ // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
+ // when this coercion occurs, we would be changing the
+ // field `ptr` from a thin pointer of type `*mut [i32;
+ // 3]` to a fat pointer of type `*mut [i32]` (with
+ // extra data `3`). **The purpose of this check is to
+ // make sure that we know how to do this conversion.**
+ //
+ // To check if this impl is legal, we would walk down
+ // the fields of `Foo` and consider their types with
+ // both substitutes. We are looking to find that
+ // exactly one (non-phantom) field has changed its
+ // type, which we will expect to be the pointer that
+ // is becoming fat (we could probably generalize this
+ // to multiple thin pointers of the same type becoming
+ // fat, but we don't). In this case:
+ //
+ // - `extra` has type `T` before and type `T` after
+ // - `ptr` has type `*mut U` before and type `*mut V` after
+ //
+ // Since just one field changed, we would then check
+ // that `*mut U: CoerceUnsized<*mut V>` is implemented
+ // (in other words, that we know how to do this
+ // conversion). This will work out because `U:
+ // Unsize<V>`, and we have a builtin rule that `*mut
+ // U` can be coerced to `*mut V` if `U: Unsize<V>`.
+ let fields = &def_a.non_enum_variant().fields;
+ let diff_fields = fields
+ .iter()
+ .enumerate()
+ .filter_map(|(i, f)| {
+ let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
+
+ if tcx.type_of(f.did).is_phantom_data() {
+ // Ignore PhantomData fields
+ return None;
+ }
+
+ // Ignore fields that aren't changed; it may
+ // be that we could get away with subtyping or
+ // something more accepting, but we use
+ // equality because we want to be able to
+ // perform this check without computing
+ // variance where possible. (This is because
+ // we may have to evaluate constraint
+ // expressions in the course of execution.)
+ // See e.g., #41936.
+ if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
+ if ok.obligations.is_empty() {
+ return None;
+ }
+ }
+
+ // Collect up all fields that were significantly changed
+ // i.e., those that contain T in coerce_unsized T -> U
+ Some((i, a, b))
+ })
+ .collect::<Vec<_>>();
+
+ if diff_fields.is_empty() {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0374,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures with one field \
+ being coerced, none found"
+ )
+ .emit();
+ return err_info;
+ } else if diff_fields.len() > 1 {
+ let item = tcx.hir().expect_item(impl_did);
+ let span =
+ if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
+ t.path.span
+ } else {
+ tcx.def_span(impl_did)
+ };
+
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0375,
+ "implementing the trait \
+ `CoerceUnsized` requires multiple \
+ coercions"
+ )
+ .note(
+ "`CoerceUnsized` may only be implemented for \
+ a coercion between structures with one field being coerced",
+ )
+ .note(&format!(
+ "currently, {} fields need coercions: {}",
+ diff_fields.len(),
+ diff_fields
+ .iter()
+ .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
+ .collect::<Vec<_>>()
+ .join(", ")
+ ))
+ .span_label(span, "requires multiple coercions")
+ .emit();
+ return err_info;
+ }
+
+ let (i, a, b) = diff_fields[0];
+ let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
+ (a, b, coerce_unsized_trait, Some(kind))
+ }
+
+ _ => {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0376,
+ "the trait `CoerceUnsized` may only be implemented \
+ for a coercion between structures"
+ )
+ .emit();
+ return err_info;
+ }
+ };
+
+ // Register an obligation for `A: Trait<B>`.
+ let cause = traits::ObligationCause::misc(span, impl_hir_id);
+ let predicate =
+ predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
+ let errors = traits::fully_solve_obligation(&infcx, predicate);
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+
+ // Finally, resolve all regions.
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
+
+ CoerceUnsizedInfo { custom_kind: kind }
+}
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 52aad636f..2890c149b 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -58,7 +58,7 @@ const ADD_ATTR: &str =
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
- let impl_def_id = item.def_id;
+ let impl_def_id = item.owner_id;
if let Some(def_id) = def_id.as_local() {
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation and
@@ -89,7 +89,7 @@ impl<'tcx> InherentCollect<'tcx> {
for impl_item in items {
if !self
.tcx
- .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -105,7 +105,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
- self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+ self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id.def_id);
} else {
bug!("unexpected self type: {:?}", self_ty);
}
@@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
for item in items {
if !self
.tcx
- .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
@@ -177,7 +177,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
fn check_item(&mut self, id: hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
@@ -186,7 +186,7 @@ impl<'tcx> InherentCollect<'tcx> {
return;
};
- let self_ty = self.tcx.type_of(item.def_id);
+ let self_ty = self.tcx.type_of(item.owner_id);
match *self_ty.kind() {
ty::Adt(def, _) => {
self.check_def_id(item, self_ty, def.did());
@@ -220,7 +220,9 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Ref(..)
| ty::Never
| ty::FnPtr(_)
- | ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
+ | ty::Tuple(..) => {
+ self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
+ }
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
@@ -241,7 +243,7 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
- bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty);
+ bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
}
ty::Error(_) => {}
}
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 03e076bf5..972769eb1 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -58,6 +58,37 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
+ fn check_for_duplicate_items_in_impl(&self, impl_: DefId) {
+ let impl_items = self.tcx.associated_items(impl_);
+
+ let mut seen_items = FxHashMap::default();
+ for impl_item in impl_items.in_definition_order() {
+ let span = self.tcx.def_span(impl_item.def_id);
+ let ident = impl_item.ident(self.tcx);
+
+ let norm_ident = ident.normalize_to_macros_2_0();
+ match seen_items.entry(norm_ident) {
+ Entry::Occupied(entry) => {
+ let former = entry.get();
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0592,
+ "duplicate definitions with name `{}`",
+ ident,
+ );
+ err.span_label(span, format!("duplicate definitions for `{}`", ident));
+ err.span_label(*former, format!("other definition for `{}`", ident));
+
+ err.emit();
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(span);
+ }
+ }
+ }
+ }
+
fn check_for_common_items_in_impls(
&self,
impl1: DefId,
@@ -117,29 +148,22 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
// inherent impls without warning.
SkipLeakCheck::Yes,
overlap_mode,
- |overlap| {
- self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
- false
- },
- || true,
- );
+ )
+ .map_or(true, |overlap| {
+ self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
+ false
+ });
}
fn check_item(&mut self, id: hir::ItemId) {
- let def_kind = self.tcx.def_kind(id.def_id);
+ let def_kind = self.tcx.def_kind(id.owner_id);
if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
return;
}
- let impls = self.tcx.inherent_impls(id.def_id);
+ let impls = self.tcx.inherent_impls(id.owner_id);
- // If there is only one inherent impl block,
- // there is nothing to overlap check it with
- if impls.len() <= 1 {
- return;
- }
-
- let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id());
+ let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
let impls_items = impls
.iter()
@@ -152,6 +176,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
const ALLOCATING_ALGO_THRESHOLD: usize = 500;
if impls.len() < ALLOCATING_ALGO_THRESHOLD {
for (i, &(&impl1_def_id, impl_items1)) in impls_items.iter().enumerate() {
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &(&impl2_def_id, impl_items2) in &impls_items[(i + 1)..] {
if self.impls_have_common_items(impl_items1, impl_items2) {
self.check_for_overlapping_inherent_impls(
@@ -290,6 +316,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
impl_blocks.sort_unstable();
for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
+ self.check_for_duplicate_items_in_impl(impl1_def_id);
+
for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
let &(&impl2_def_id, impl_items2) = &impls_items[impl2_items_idx];
if self.impls_have_common_items(impl_items1, impl_items2) {
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index ae9ebe590..ae9ebe590 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1608550aa..bb45c3823 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,10 +2,9 @@
//! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IgnoreRegions;
@@ -43,7 +42,7 @@ fn do_orphan_check_impl<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let trait_def_id = trait_ref.def_id;
- let item = tcx.hir().item(hir::ItemId { def_id });
+ let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else {
bug!("{:?} is not an impl: {:?}", def_id, item);
};
@@ -102,7 +101,7 @@ fn do_orphan_check_impl<'tcx>(
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
}
- match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
tcx,
@@ -229,12 +228,8 @@ fn emit_orphan_check_error<'tcx>(
"only traits defined in the current crate {msg}"
);
err.span_label(sp, "impl doesn't use only types from inside the current crate");
- for (ty, is_target_ty) in &tys {
- let mut ty = *ty;
- tcx.infer_ctxt().enter(|infcx| {
- // Remove the lifetimes unnecessary for this error.
- ty = infcx.freshen(ty);
- });
+ for &(mut ty, is_target_ty) in &tys {
+ ty = tcx.erase_regions(ty);
ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant.
// You can think of this as the reverse of `resolve_vars_if_possible`.
@@ -264,7 +259,7 @@ fn emit_orphan_check_error<'tcx>(
};
let msg = format!("{} is not defined in the current crate{}", ty, postfix);
- if *is_target_ty {
+ if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
err.span_label(self_ty_span, &msg);
} else {
@@ -417,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
tcx.hir().local_def_id_to_hir_id(impl_def_id),
tcx.def_span(impl_def_id),
- |err| {
- let item_span = tcx.def_span(self_type_did);
- let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
- let mut err = err.build(&format!(
+ DelayDm(|| {
+ format!(
"cross-crate traits with a default impl, like `{}`, \
should not be specialized",
tcx.def_path_str(trait_ref.def_id),
- ));
+ )
+ }),
+ |lint| {
+ let item_span = tcx.def_span(self_type_did);
+ let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- err.note(&format!("`{}` is mentioned multiple times", arg));
+ lint.note(&format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
- err.note(&format!("`{}` is not a generic parameter", arg));
+ lint.note(&format!("`{}` is not a generic parameter", arg));
}
}
- err.span_note(
+ lint.span_note(
item_span,
&format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),
- );
- err.emit();
+ )
},
);
}
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index e45fb5fe4..a34815b45 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -13,7 +13,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
- if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
@@ -26,6 +26,12 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path()
)
+ .span_suggestion_verbose(
+ item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
+ "remove `unsafe` from this trait implementation",
+ "",
+ rustc_errors::Applicability::MachineApplicable,
+ )
.emit();
}
@@ -37,6 +43,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path()
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
@@ -48,6 +66,18 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 45a5eca70..346d2e2fc 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -15,46 +15,41 @@
//! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::AstConv;
-use crate::bounds::Bounds;
use crate::check::intrinsic::intrinsic_operation_unsafety;
-use crate::constrained_generic_params as cgp;
use crate::errors;
-use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, HirId, Node};
+use rustc_hir::{GenericParamKind, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::Discr;
-use rustc_middle::ty::util::IntTypeExt;
+use rustc_middle::ty::util::{Discr, IntTypeExt};
+use rustc_middle::ty::ReprOptions;
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
-use rustc_middle::ty::{ReprOptions, ToPredicate};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use rustc_target::spec::{abi, SanitizerSet};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter;
+mod generics_of;
mod item_bounds;
+mod lifetimes;
+mod predicates_of;
mod type_of;
-#[derive(Debug)]
-struct OnlySelfBounds(bool);
-
///////////////////////////////////////////////////////////////////////////
// Main entry point
@@ -63,19 +58,21 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
}
pub fn provide(providers: &mut Providers) {
+ lifetimes::provide(providers);
*providers = Providers {
opt_const_param_of: type_of::opt_const_param_of,
type_of: type_of::type_of,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
- generics_of,
- predicates_of,
+ generics_of: generics_of::generics_of,
+ predicates_of: predicates_of::predicates_of,
predicates_defined_on,
- explicit_predicates_of,
- super_predicates_of,
- super_predicates_that_define_assoc_type,
- trait_explicit_predicates_and_bounds,
- type_param_predicates,
+ explicit_predicates_of: predicates_of::explicit_predicates_of,
+ super_predicates_of: predicates_of::super_predicates_of,
+ super_predicates_that_define_assoc_type:
+ predicates_of::super_predicates_that_define_assoc_type,
+ trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
+ type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
fn_sig,
@@ -103,13 +100,12 @@ pub fn provide(providers: &mut Providers) {
/// It's also used for the bodies of items like structs where the body (the fields)
/// are just signatures.
///
-/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// This is in contrast to `FnCtxt`, which is used to type-check bodies of
/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
///
/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
/// while `FnCtxt` does do inference.
///
-/// [`FnCtxt`]: crate::check::FnCtxt
/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
///
/// # Trait predicates
@@ -430,7 +426,6 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
self,
- self.tcx,
span,
item_def_id,
item_segment,
@@ -449,8 +444,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
- let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+ let item = self
+ .tcx
+ .hir()
+ .expect_item(self.tcx.hir().get_parent_item(self.hir_id()).def_id);
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
@@ -571,164 +568,10 @@ fn get_new_lifetime_name<'tcx>(
(1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
}
-/// Returns the predicates defined on `item_def_id` of the form
-/// `X: Foo` where `X` is the type parameter `def_id`.
-#[instrument(level = "trace", skip(tcx))]
-fn type_param_predicates(
- tcx: TyCtxt<'_>,
- (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
-) -> ty::GenericPredicates<'_> {
- use rustc_hir::*;
-
- // In the AST, bounds can derive from two places. Either
- // written inline like `<T: Foo>` or in a where-clause like
- // `where T: Foo`.
-
- let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let param_owner = tcx.hir().ty_param_owner(def_id);
- let generics = tcx.generics_of(param_owner);
- let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
-
- // Don't look for bounds where the type parameter isn't in scope.
- let parent = if item_def_id == param_owner.to_def_id() {
- None
- } else {
- tcx.generics_of(item_def_id).parent
- };
-
- let mut result = parent
- .map(|parent| {
- let icx = ItemCtxt::new(tcx, parent);
- icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
- })
- .unwrap_or_default();
- let mut extend = None;
-
- let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
- let ast_generics = match tcx.hir().get(item_hir_id) {
- Node::TraitItem(item) => &item.generics,
-
- Node::ImplItem(item) => &item.generics,
-
- Node::Item(item) => {
- match item.kind {
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::Impl(hir::Impl { ref generics, .. })
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- })
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => generics,
- ItemKind::Trait(_, _, ref generics, ..) => {
- // Implied `Self: Trait` and supertrait bounds.
- if param_id == item_hir_id {
- let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
- extend =
- Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
- }
- generics
- }
- _ => return result,
- }
- }
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Fn(_, _, ref generics) => generics,
- _ => return result,
- },
-
- _ => return result,
- };
-
- let icx = ItemCtxt::new(tcx, item_def_id);
- let extra_predicates = extend.into_iter().chain(
- icx.type_parameter_bounds_in_generics(
- ast_generics,
- param_id,
- ty,
- OnlySelfBounds(true),
- Some(assoc_name),
- )
- .into_iter()
- .filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
- _ => false,
- }),
- );
- result.predicates =
- tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
- result
-}
-
-impl<'tcx> ItemCtxt<'tcx> {
- /// Finds bounds from `hir::Generics`. This requires scanning through the
- /// AST. We do this to avoid having to convert *all* the bounds, which
- /// would create artificial cycles. Instead, we can only convert the
- /// bounds for a type parameter `X` if `X::Foo` is used.
- #[instrument(level = "trace", skip(self, ast_generics))]
- fn type_parameter_bounds_in_generics(
- &self,
- ast_generics: &'tcx hir::Generics<'tcx>,
- param_id: hir::HirId,
- ty: Ty<'tcx>,
- only_self_bounds: OnlySelfBounds,
- assoc_name: Option<Ident>,
- ) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
- trace!(?param_def_id);
- ast_generics
- .predicates
- .iter()
- .filter_map(|wp| match *wp {
- hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
- _ => None,
- })
- .flat_map(|bp| {
- let bt = if bp.is_param_bound(param_def_id) {
- Some(ty)
- } else if !only_self_bounds.0 {
- Some(self.to_ty(bp.bounded_ty))
- } else {
- None
- };
- let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
-
- bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
- |(_, b, _)| match assoc_name {
- Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
- None => true,
- },
- )
- })
- .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
- .collect()
- }
-
- #[instrument(level = "trace", skip(self))]
- fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
- match b {
- hir::GenericBound::Trait(poly_trait_ref, _) => {
- let trait_ref = &poly_trait_ref.trait_ref;
- if let Some(trait_did) = trait_ref.trait_def_id() {
- self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
- } else {
- false
- }
- }
- _ => false,
- }
- }
-}
-
fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!("convert: item {} with id {}", it.ident, it.hir_id());
- let def_id = item_id.def_id;
+ let def_id = item_id.owner_id.def_id;
match it.kind {
// These don't define types.
@@ -740,11 +583,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
hir::ItemKind::ForeignMod { items, .. } => {
for item in items {
let item = tcx.hir().foreign_item(item.id);
- tcx.ensure().generics_of(item.def_id);
- tcx.ensure().type_of(item.def_id);
- tcx.ensure().predicates_of(item.def_id);
+ tcx.ensure().generics_of(item.owner_id);
+ tcx.ensure().type_of(item.owner_id);
+ tcx.ensure().predicates_of(item.owner_id);
match item.kind {
- hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
+ hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id),
hir::ForeignItemKind::Static(..) => {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
@@ -840,20 +683,21 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
- tcx.ensure().generics_of(trait_item_id.def_id);
+ let def_id = trait_item_id.owner_id;
+ tcx.ensure().generics_of(def_id);
match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
- tcx.ensure().type_of(trait_item_id.def_id);
- tcx.ensure().fn_sig(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
+ tcx.ensure().fn_sig(def_id);
}
hir::TraitItemKind::Const(.., Some(_)) => {
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
}
hir::TraitItemKind::Const(hir_ty, _) => {
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().type_of(def_id);
// Account for `const C: _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
@@ -863,8 +707,8 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, Some(_)) => {
- tcx.ensure().item_bounds(trait_item_id.def_id);
- tcx.ensure().type_of(trait_item_id.def_id);
+ tcx.ensure().item_bounds(def_id);
+ tcx.ensure().type_of(def_id);
// Account for `type T = _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
@@ -872,7 +716,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
hir::TraitItemKind::Type(_, None) => {
- tcx.ensure().item_bounds(trait_item_id.def_id);
+ tcx.ensure().item_bounds(def_id);
// #74612: Visit and try to find bad placeholders
// even if there is no concrete type.
let mut visitor = HirPlaceholderCollector::default();
@@ -882,11 +726,11 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
}
};
- tcx.ensure().predicates_of(trait_item_id.def_id);
+ tcx.ensure().predicates_of(def_id);
}
fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
- let def_id = impl_item_id.def_id;
+ let def_id = impl_item_id.owner_id;
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
@@ -895,7 +739,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
hir::ImplItemKind::Fn(..) => {
tcx.ensure().fn_sig(def_id);
}
- hir::ImplItemKind::TyAlias(_) => {
+ hir::ImplItemKind::Type(_) => {
// Account for `type T = _;`
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
@@ -1095,96 +939,6 @@ fn adt_def<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AdtDef<'tcx> {
tcx.alloc_adt_def(def_id.to_def_id(), kind, variants, repr)
}
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
- debug!("super_predicates(trait_def_id={:?})", trait_def_id);
- tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
-}
-
-/// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
-fn super_predicates_that_define_assoc_type(
- tcx: TyCtxt<'_>,
- (trait_def_id, assoc_name): (DefId, Option<Ident>),
-) -> ty::GenericPredicates<'_> {
- debug!(
- "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
- trait_def_id, assoc_name
- );
- if trait_def_id.is_local() {
- debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
- let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
-
- let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
- bug!("trait_node_id {} is not an item", trait_hir_id);
- };
-
- let (generics, bounds) = match item.kind {
- hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
- hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
- _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
- };
-
- let icx = ItemCtxt::new(tcx, trait_def_id);
-
- // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
- let self_param_ty = tcx.types.self_param;
- let superbounds1 = if let Some(assoc_name) = assoc_name {
- <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
- &icx,
- self_param_ty,
- bounds,
- assoc_name,
- )
- } else {
- <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
- };
-
- let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
- // Convert any explicit superbounds in the where-clause,
- // e.g., `trait Foo where Self: Bar`.
- // In the case of trait aliases, however, we include all bounds in the where-clause,
- // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
- // as one of its "superpredicates".
- let is_trait_alias = tcx.is_trait_alias(trait_def_id);
- let superbounds2 = icx.type_parameter_bounds_in_generics(
- generics,
- item.hir_id(),
- self_param_ty,
- OnlySelfBounds(!is_trait_alias),
- assoc_name,
- );
-
- // Combine the two lists to form the complete set of superbounds:
- let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
- debug!(?superbounds);
-
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
- if assoc_name.is_none() {
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
- for &(pred, span) in superbounds {
- debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
- tcx.at(span).super_predicates_of(bound.def_id());
- }
- }
- }
-
- ty::GenericPredicates { parent: None, predicates: superbounds }
- } else {
- // if `assoc_name` is None, then the query should've been redirected to an
- // external provider
- assert!(assoc_name.is_some());
- tcx.super_predicates_of(trait_def_id)
- }
-}
-
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
let item = tcx.hir().expect_item(def_id.expect_local());
@@ -1256,7 +1010,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
- if !tcx.impl_defaultness(item.id.def_id).has_value() {
+ if !tcx.impl_defaultness(item.id.owner_id).has_value() {
tcx.sess
.struct_span_err(
item.span,
@@ -1326,475 +1080,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
)
}
-fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
- struct LateBoundRegionsDetector<'tcx> {
- tcx: TyCtxt<'tcx>,
- outer_index: ty::DebruijnIndex,
- has_late_bound_regions: Option<Span>,
- }
-
- impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
- fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
- match ty.kind {
- hir::TyKind::BareFn(..) => {
- self.outer_index.shift_in(1);
- intravisit::walk_ty(self, ty);
- self.outer_index.shift_out(1);
- }
- _ => intravisit::walk_ty(self, ty),
- }
- }
-
- fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
- self.outer_index.shift_in(1);
- intravisit::walk_poly_trait_ref(self, tr);
- self.outer_index.shift_out(1);
- }
-
- fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
- if self.has_late_bound_regions.is_some() {
- return;
- }
-
- match self.tcx.named_region(lt.hir_id) {
- Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
- Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
- Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
- self.has_late_bound_regions = Some(lt.span);
- }
- }
- }
- }
-
- fn has_late_bound_regions<'tcx>(
- tcx: TyCtxt<'tcx>,
- generics: &'tcx hir::Generics<'tcx>,
- decl: &'tcx hir::FnDecl<'tcx>,
- ) -> Option<Span> {
- let mut visitor = LateBoundRegionsDetector {
- tcx,
- outer_index: ty::INNERMOST,
- has_late_bound_regions: None,
- };
- for param in generics.params {
- if let GenericParamKind::Lifetime { .. } = param.kind {
- if tcx.is_late_bound(param.hir_id) {
- return Some(param.span);
- }
- }
- }
- visitor.visit_fn_decl(decl);
- visitor.has_late_bound_regions
- }
-
- match node {
- Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
- _ => None,
- },
- Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, &item.generics, sig.decl)
- }
- _ => None,
- },
- Node::ForeignItem(item) => match item.kind {
- hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
- has_late_bound_regions(tcx, generics, fn_decl)
- }
- _ => None,
- },
- Node::Item(item) => match item.kind {
- hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
- has_late_bound_regions(tcx, generics, sig.decl)
- }
- _ => None,
- },
- _ => None,
- }
-}
-
-struct AnonConstInParamTyDetector {
- in_param_ty: bool,
- found_anon_const_in_param_ty: bool,
- ct: HirId,
-}
-
-impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
- fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
- if let GenericParamKind::Const { ty, default: _ } = p.kind {
- let prev = self.in_param_ty;
- self.in_param_ty = true;
- self.visit_ty(ty);
- self.in_param_ty = prev;
- }
- }
-
- fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
- if self.in_param_ty && self.ct == c.hir_id {
- self.found_anon_const_in_param_ty = true;
- } else {
- intravisit::walk_anon_const(self, c)
- }
- }
-}
-
-fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
- use rustc_hir::*;
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
- let node = tcx.hir().get(hir_id);
- let parent_def_id = match node {
- Node::ImplItem(_)
- | Node::TraitItem(_)
- | Node::Variant(_)
- | Node::Ctor(..)
- | Node::Field(_) => {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- Some(parent_id.to_def_id())
- }
- // FIXME(#43408) always enable this once `lazy_normalization` is
- // stable enough and does not need a feature gate anymore.
- Node::AnonConst(_) => {
- let parent_def_id = tcx.hir().get_parent_item(hir_id);
-
- let mut in_param_ty = false;
- for (_parent, node) in tcx.hir().parent_iter(hir_id) {
- if let Some(generics) = node.generics() {
- let mut visitor = AnonConstInParamTyDetector {
- in_param_ty: false,
- found_anon_const_in_param_ty: false,
- ct: hir_id,
- };
-
- visitor.visit_generics(generics);
- in_param_ty = visitor.found_anon_const_in_param_ty;
- break;
- }
- }
-
- if in_param_ty {
- // We do not allow generic parameters in anon consts if we are inside
- // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
- None
- } else if tcx.lazy_normalization() {
- if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
- // If the def_id we are calling generics_of on is an anon ct default i.e:
- //
- // struct Foo<const N: usize = { .. }>;
- // ^^^ ^ ^^^^^^ def id of this anon const
- // ^ ^ param_id
- // ^ parent_def_id
- //
- // then we only want to return generics for params to the left of `N`. If we don't do that we
- // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
- //
- // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
- // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
- // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
- //
- // We fix this by having this function return the parent's generics ourselves and truncating the
- // generics to only include non-forward declared params (with the exception of the `Self` ty)
- //
- // For the above code example that means we want `substs: []`
- // For the following struct def we want `substs: [N#0]` when generics_of is called on
- // the def id of the `{ N + 1 }` anon const
- // struct Foo<const N: usize, const M: usize = { N + 1 }>;
- //
- // This has some implications for how we get the predicates available to the anon const
- // see `explicit_predicates_of` for more information on this
- let generics = tcx.generics_of(parent_def_id.to_def_id());
- let param_def = tcx.hir().local_def_id(param_id).to_def_id();
- let param_def_idx = generics.param_def_id_to_index[&param_def];
- // In the above example this would be .params[..N#0]
- let params = generics.params[..param_def_idx as usize].to_owned();
- let param_def_id_to_index =
- params.iter().map(|param| (param.def_id, param.index)).collect();
-
- return ty::Generics {
- // we set the parent of these generics to be our parent's parent so that we
- // dont end up with substs: [N, M, N] for the const default on a struct like this:
- // struct Foo<const N: usize, const M: usize = { ... }>;
- parent: generics.parent,
- parent_count: generics.parent_count,
- params,
- param_def_id_to_index,
- has_self: generics.has_self,
- has_late_bound_regions: generics.has_late_bound_regions,
- };
- }
-
- // HACK(eddyb) this provides the correct generics when
- // `feature(generic_const_expressions)` is enabled, so that const expressions
- // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
- //
- // Note that we do not supply the parent generics when using
- // `min_const_generics`.
- Some(parent_def_id.to_def_id())
- } else {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
- match parent_node {
- // HACK(eddyb) this provides the correct generics for repeat
- // expressions' count (i.e. `N` in `[x; N]`), and explicit
- // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
- // as they shouldn't be able to cause query cycle errors.
- Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- if constant.hir_id() == hir_id =>
- {
- Some(parent_def_id.to_def_id())
- }
- Node::Variant(Variant { disr_expr: Some(ref constant), .. })
- if constant.hir_id == hir_id =>
- {
- Some(parent_def_id.to_def_id())
- }
- Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
- Some(tcx.typeck_root_def_id(def_id))
- }
- // Exclude `GlobalAsm` here which cannot have generics.
- Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
- if asm.operands.iter().any(|(op, _op_sp)| match op {
- hir::InlineAsmOperand::Const { anon_const }
- | hir::InlineAsmOperand::SymFn { anon_const } => {
- anon_const.hir_id == hir_id
- }
- _ => false,
- }) =>
- {
- Some(parent_def_id.to_def_id())
- }
- _ => None,
- }
- }
- }
- Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
- Some(tcx.typeck_root_def_id(def_id))
- }
- Node::Item(item) => match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy {
- origin:
- hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
- in_trait,
- ..
- }) => {
- if in_trait {
- assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
- } else {
- assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
- }
- Some(fn_def_id.to_def_id())
- }
- ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
- let parent_id = tcx.hir().get_parent_item(hir_id);
- assert_ne!(parent_id, CRATE_DEF_ID);
- debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
- // Opaque types are always nested within another item, and
- // inherit the generics of the item.
- Some(parent_id.to_def_id())
- }
- _ => None,
- },
- _ => None,
- };
-
- enum Defaults {
- Allowed,
- // See #36887
- FutureCompatDisallowed,
- Deny,
- }
-
- let no_generics = hir::Generics::empty();
- let ast_generics = node.generics().unwrap_or(&no_generics);
- let (opt_self, allow_defaults) = match node {
- Node::Item(item) => {
- match item.kind {
- ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
- // Add in the self type parameter.
- //
- // Something of a hack: use the node id for the trait, also as
- // the node id for the Self type parameter.
- let opt_self = Some(ty::GenericParamDef {
- index: 0,
- name: kw::SelfUpper,
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type {
- has_default: false,
- synthetic: false,
- },
- });
-
- (opt_self, Defaults::Allowed)
- }
- ItemKind::TyAlias(..)
- | ItemKind::Enum(..)
- | ItemKind::Struct(..)
- | ItemKind::OpaqueTy(..)
- | ItemKind::Union(..) => (None, Defaults::Allowed),
- _ => (None, Defaults::FutureCompatDisallowed),
- }
- }
-
- // GATs
- Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
- (None, Defaults::Deny)
- }
- Node::ImplItem(item) if matches!(item.kind, ImplItemKind::TyAlias(..)) => {
- (None, Defaults::Deny)
- }
-
- _ => (None, Defaults::FutureCompatDisallowed),
- };
-
- let has_self = opt_self.is_some();
- let mut parent_has_self = false;
- let mut own_start = has_self as u32;
- let parent_count = parent_def_id.map_or(0, |def_id| {
- let generics = tcx.generics_of(def_id);
- assert!(!has_self);
- parent_has_self = generics.has_self;
- own_start = generics.count() as u32;
- generics.parent_count + generics.params.len()
- });
-
- let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
-
- if let Some(opt_self) = opt_self {
- params.push(opt_self);
- }
-
- let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
- params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
- name: param.name.ident().name,
- index: own_start + i as u32,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Lifetime,
- }));
-
- // Now create the real type and const parameters.
- let type_start = own_start - has_self as u32 + params.len() as u32;
- let mut i = 0;
-
- const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions";
-
- params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => None,
- GenericParamKind::Type { ref default, synthetic, .. } => {
- if default.is_some() {
- match allow_defaults {
- Defaults::Allowed => {}
- Defaults::FutureCompatDisallowed
- if tcx.features().default_type_parameter_fallback => {}
- Defaults::FutureCompatDisallowed => {
- tcx.struct_span_lint_hir(
- lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
- param.hir_id,
- param.span,
- |lint| {
- lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
- },
- );
- }
- Defaults::Deny => {
- tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
- }
- }
- }
-
- let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
-
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
- name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind,
- };
- i += 1;
- Some(param_def)
- }
- GenericParamKind::Const { default, .. } => {
- if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
- tcx.sess.span_err(
- param.span,
- "defaults for const parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions",
- );
- }
-
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
- name: param.name.ident().name,
- def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
- pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
- };
- i += 1;
- Some(param_def)
- }
- }));
-
- // provide junk type parameter defs - the only place that
- // cares about anything but the length is instantiation,
- // and we don't do that for closures.
- if let Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
- ..
- }) = node
- {
- let dummy_args = if gen.is_some() {
- &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
- } else {
- &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
- };
-
- params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
- index: type_start + i as u32,
- name: Symbol::intern(arg),
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
- }));
- }
-
- // provide junk type parameter defs for const blocks.
- if let Node::AnonConst(_) = node {
- let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
- if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
- params.push(ty::GenericParamDef {
- index: type_start,
- name: Symbol::intern("<const_ty>"),
- def_id,
- pure_wrt_drop: false,
- kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
- });
- }
- }
-
- let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
-
- ty::Generics {
- parent: parent_def_id,
- parent_count,
- params,
- param_def_id_to_index,
- has_self: has_self || parent_has_self,
- has_late_bound_regions: has_late_bound_regions(tcx, node),
- }
-}
-
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
@@ -1858,7 +1143,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
}
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
- // Do not try to inference the return type for a impl method coming from a trait
+ // Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
&& i.of_trait.is_some()
@@ -2001,15 +1286,46 @@ fn infer_return_ty_for_fn_sig<'tcx>(
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
- match tcx.hir().expect_item(def_id.expect_local()).kind {
+ let item = tcx.hir().expect_item(def_id.expect_local());
+ match item.kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
- <dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+ <dyn AstConv<'_>>::instantiate_mono_trait_ref(
+ &icx,
+ ast_trait_ref,
+ selfty,
+ check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+ )
}),
_ => bug!(),
}
}
+fn check_impl_constness(
+ tcx: TyCtxt<'_>,
+ constness: hir::Constness,
+ ast_trait_ref: &hir::TraitRef<'_>,
+) -> ty::BoundConstness {
+ match constness {
+ hir::Constness::Const => {
+ if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
+ let trait_name = tcx.item_name(trait_def_id).to_string();
+ tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
+ trait_ref_span: ast_trait_ref.path.span,
+ trait_name,
+ local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
+ marking: (),
+ adding: (),
+ });
+ ty::BoundConstness::NotConst
+ } else {
+ ty::BoundConstness::ConstIfConst
+ }
+ },
+ hir::Constness::NotConst => ty::BoundConstness::NotConst,
+ }
+}
+
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
let item = tcx.hir().expect_item(def_id.expect_local());
@@ -2091,451 +1407,6 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
result
}
-/// Returns a list of all type predicates (explicit and implicit) for the definition with
-/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
-/// `Self: Trait` predicates for traits.
-fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- let mut result = tcx.predicates_defined_on(def_id);
-
- if tcx.is_trait(def_id) {
- // For traits, add `Self: Trait` predicate. This is
- // not part of the predicates that a user writes, but it
- // is something that one must prove in order to invoke a
- // method or project an associated type.
- //
- // In the chalk setup, this predicate is not part of the
- // "predicates" for a trait item. But it is useful in
- // rustc because if you directly (e.g.) invoke a trait
- // method like `Trait::method(...)`, you must naturally
- // prove that the trait applies to the types that were
- // used, and adding the predicate into this list ensures
- // that this is done.
- //
- // We use a DUMMY_SP here as a way to signal trait bounds that come
- // from the trait itself that *shouldn't* be shown as the source of
- // an obligation and instead be skipped. Otherwise we'd use
- // `tcx.def_span(def_id);`
-
- let constness = if tcx.has_attr(def_id, sym::const_trait) {
- ty::BoundConstness::ConstIfConst
- } else {
- ty::BoundConstness::NotConst
- };
-
- let span = rustc_span::DUMMY_SP;
- result.predicates =
- tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
- ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
- span,
- ))));
- }
- debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
- result
-}
-
-/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
-/// N.B., this does not include any implied/inferred constraints.
-#[instrument(level = "trace", skip(tcx), ret)]
-fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- use rustc_hir::*;
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let node = tcx.hir().get(hir_id);
-
- let mut is_trait = None;
- let mut is_default_impl_trait = None;
-
- let icx = ItemCtxt::new(tcx, def_id);
-
- const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
-
- // We use an `IndexSet` to preserves order of insertion.
- // Preserving the order of insertion is important here so as not to break UI tests.
- let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
-
- let ast_generics = match node {
- Node::TraitItem(item) => item.generics,
-
- Node::ImplItem(item) => item.generics,
-
- Node::Item(item) => {
- match item.kind {
- ItemKind::Impl(ref impl_) => {
- if impl_.defaultness.is_default() {
- is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
- }
- &impl_.generics
- }
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics) => *generics,
-
- ItemKind::Trait(_, _, ref generics, ..) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::TraitAlias(ref generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id));
- *generics
- }
- ItemKind::OpaqueTy(OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- ..
- }) => {
- // return-position impl trait
- //
- // We don't inherit predicates from the parent here:
- // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
- // then the return type is `f::<'static, T>::{{opaque}}`.
- //
- // If we inherited the predicates of `f` then we would
- // require that `T: 'static` to show that the return
- // type is well-formed.
- //
- // The only way to have something with this opaque type
- // is from the return type of the containing function,
- // which will ensure that the function's predicates
- // hold.
- return ty::GenericPredicates { parent: None, predicates: &[] };
- }
- ItemKind::OpaqueTy(OpaqueTy {
- ref generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
- ..
- }) => {
- // type-alias impl trait
- generics
- }
-
- _ => NO_GENERICS,
- }
- }
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Static(..) => NO_GENERICS,
- ForeignItemKind::Fn(_, _, ref generics) => *generics,
- ForeignItemKind::Type => NO_GENERICS,
- },
-
- _ => NO_GENERICS,
- };
-
- let generics = tcx.generics_of(def_id);
- let parent_count = generics.parent_count as u32;
- let has_own_self = generics.has_self && parent_count == 0;
-
- // Below we'll consider the bounds on the type parameters (including `Self`)
- // and the explicit where-clauses, but to get the full set of predicates
- // on a trait we need to add in the supertrait bounds and bounds found on
- // associated types.
- if let Some(_trait_ref) = is_trait {
- predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
- }
-
- // In default impls, we can assume that the self type implements
- // the trait. So in:
- //
- // default impl Foo for Bar { .. }
- //
- // we add a default where clause `Foo: Bar`. We do a similar thing for traits
- // (see below). Recall that a default impl is not itself an impl, but rather a
- // set of defaults that can be incorporated into another impl.
- if let Some(trait_ref) = is_default_impl_trait {
- predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
- }
-
- // Collect the region predicates that were declared inline as
- // well. In the case of parameters declared on a fn or method, we
- // have to be careful to only iterate over early-bound regions.
- let mut index = parent_count
- + has_own_self as u32
- + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
-
- trace!(?predicates);
- trace!(?ast_generics);
-
- // Collect the predicates that were written inline by the user on each
- // type parameter (e.g., `<T: Foo>`).
- for param in ast_generics.params {
- match param.kind {
- // We already dealt with early bound lifetimes above.
- GenericParamKind::Lifetime { .. } => (),
- GenericParamKind::Type { .. } => {
- let name = param.name.ident().name;
- let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
- index += 1;
-
- let mut bounds = Bounds::default();
- // Params are implicitly sized unless a `?Sized` bound is found
- <dyn AstConv<'_>>::add_implicitly_sized(
- &icx,
- &mut bounds,
- &[],
- Some((param.hir_id, ast_generics.predicates)),
- param.span,
- );
- trace!(?bounds);
- predicates.extend(bounds.predicates(tcx, param_ty));
- trace!(?predicates);
- }
- GenericParamKind::Const { .. } => {
- // Bounds on const parameters are currently not possible.
- index += 1;
- }
- }
- }
-
- trace!(?predicates);
- // Add in the bounds that appear in the where-clause.
- for predicate in ast_generics.predicates {
- match predicate {
- hir::WherePredicate::BoundPredicate(bound_pred) => {
- let ty = icx.to_ty(bound_pred.bounded_ty);
- let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id);
-
- // Keep the type around in a dummy predicate, in case of no bounds.
- // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
- // is still checked for WF.
- if bound_pred.bounds.is_empty() {
- if let ty::Param(_) = ty.kind() {
- // This is a `where T:`, which can be in the HIR from the
- // transformation that moves `?Sized` to `T`'s declaration.
- // We can skip the predicate because type parameters are
- // trivially WF, but also we *should*, to avoid exposing
- // users who never wrote `where Type:,` themselves, to
- // compiler/tooling bugs from not handling WF predicates.
- } else {
- let span = bound_pred.bounded_ty.span;
- let predicate = ty::Binder::bind_with_vars(
- ty::PredicateKind::WellFormed(ty.into()),
- bound_vars,
- );
- predicates.insert((predicate.to_predicate(tcx), span));
- }
- }
-
- let mut bounds = Bounds::default();
- <dyn AstConv<'_>>::add_bounds(
- &icx,
- ty,
- bound_pred.bounds.iter(),
- &mut bounds,
- bound_vars,
- );
- predicates.extend(bounds.predicates(tcx, ty));
- }
-
- hir::WherePredicate::RegionPredicate(region_pred) => {
- let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
- predicates.extend(region_pred.bounds.iter().map(|bound| {
- let (r2, span) = match bound {
- hir::GenericBound::Outlives(lt) => {
- (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
- }
- _ => bug!(),
- };
- let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
- ty::OutlivesPredicate(r1, r2),
- ))
- .to_predicate(icx.tcx);
-
- (pred, span)
- }))
- }
-
- hir::WherePredicate::EqPredicate(..) => {
- // FIXME(#20041)
- }
- }
- }
-
- if tcx.features().generic_const_exprs {
- predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
- }
-
- let mut predicates: Vec<_> = predicates.into_iter().collect();
-
- // Subtle: before we store the predicates into the tcx, we
- // sort them so that predicates like `T: Foo<Item=U>` come
- // before uses of `U`. This avoids false ambiguity errors
- // in trait checking. See `setup_constraining_predicates`
- // for details.
- if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
- let self_ty = tcx.type_of(def_id);
- let trait_ref = tcx.impl_trait_ref(def_id);
- cgp::setup_constraining_predicates(
- tcx,
- &mut predicates,
- trait_ref,
- &mut cgp::parameters_for_impl(self_ty, trait_ref),
- );
- }
-
- ty::GenericPredicates {
- parent: generics.parent,
- predicates: tcx.arena.alloc_from_iter(predicates),
- }
-}
-
-fn const_evaluatable_predicates_of<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
- struct ConstCollector<'tcx> {
- tcx: TyCtxt<'tcx>,
- preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
- }
-
- impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
- fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- let def_id = self.tcx.hir().local_def_id(c.hir_id);
- let ct = ty::Const::from_anon_const(self.tcx, def_id);
- if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
- assert_eq!(uv.promoted, ());
- let span = self.tcx.hir().span(c.hir_id);
- self.preds.insert((
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
- .to_predicate(self.tcx),
- span,
- ));
- }
- }
-
- fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
- // Do not look into const param defaults,
- // these get checked when they are actually instantiated.
- //
- // We do not want the following to error:
- //
- // struct Foo<const N: usize, const M: usize = { N + 1 }>;
- // struct Bar<const N: usize>(Foo<N, 3>);
- }
- }
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let node = tcx.hir().get(hir_id);
-
- let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
- if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
- if let Some(of_trait) = &impl_.of_trait {
- debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
- collector.visit_trait_ref(of_trait);
- }
-
- debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
- collector.visit_ty(impl_.self_ty);
- }
-
- if let Some(generics) = node.generics() {
- debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
- collector.visit_generics(generics);
- }
-
- if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
- debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
- collector.visit_fn_decl(fn_sig.decl);
- }
- debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
-
- collector.preds
-}
-
-fn trait_explicit_predicates_and_bounds(
- tcx: TyCtxt<'_>,
- def_id: LocalDefId,
-) -> ty::GenericPredicates<'_> {
- assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
- gather_explicit_predicates_of(tcx, def_id.to_def_id())
-}
-
-fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> {
- let def_kind = tcx.def_kind(def_id);
- if let DefKind::Trait = def_kind {
- // Remove bounds on associated types from the predicates, they will be
- // returned by `explicit_item_bounds`.
- let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
- let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
-
- let is_assoc_item_ty = |ty: Ty<'tcx>| {
- // For a predicate from a where clause to become a bound on an
- // associated type:
- // * It must use the identity substs of the item.
- // * Since any generic parameters on the item are not in scope,
- // this means that the item is not a GAT, and its identity
- // substs are the same as the trait's.
- // * It must be an associated type for this trait (*not* a
- // supertrait).
- if let ty::Projection(projection) = ty.kind() {
- projection.substs == trait_identity_substs
- && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
- } else {
- false
- }
- };
-
- let predicates: Vec<_> = predicates_and_bounds
- .predicates
- .iter()
- .copied()
- .filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateKind::Projection(proj) => {
- !is_assoc_item_ty(proj.projection_ty.self_ty())
- }
- ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
- _ => true,
- })
- .collect();
- if predicates.len() == predicates_and_bounds.predicates.len() {
- predicates_and_bounds
- } else {
- ty::GenericPredicates {
- parent: predicates_and_bounds.parent,
- predicates: tcx.arena.alloc_slice(&predicates),
- }
- }
- } else {
- if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
- // In `generics_of` we set the generics' parent to be our parent's parent which means that
- // we lose out on the predicates of our actual parent if we dont return those predicates here.
- // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
- //
- // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
- // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
- // ^^^ explicit_predicates_of on
- // parent item we dont have set as the
- // parent of generics returned by `generics_of`
- //
- // In the above code we want the anon const to have predicates in its param env for `T: Trait`
- let item_def_id = tcx.hir().get_parent_item(hir_id);
- // In the above code example we would be calling `explicit_predicates_of(Foo)` here
- return tcx.explicit_predicates_of(item_def_id);
- }
- }
- gather_explicit_predicates_of(tcx, def_id)
- }
-}
-
-/// Converts a specific `GenericBound` from the AST into a set of
-/// predicates that apply to the self type. A vector is returned
-/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
-/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
-/// and `<T as Bar>::X == i32`).
-fn predicates_from_bound<'tcx>(
- astconv: &dyn AstConv<'tcx>,
- param_ty: Ty<'tcx>,
- bound: &'tcx hir::GenericBound<'tcx>,
- bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let mut bounds = Bounds::default();
- astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
- bounds.predicates(astconv.tcx(), param_ty).collect()
-}
-
fn compute_sig_of_foreign_fn_decl<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -2543,7 +1414,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
abi: abi::Abi,
) -> ty::PolyFnSig<'tcx> {
let unsafety = if abi == abi::Abi::RustIntrinsic {
- intrinsic_operation_unsafety(tcx.item_name(def_id))
+ intrinsic_operation_unsafety(tcx, def_id)
} else {
hir::Unsafety::Unsafe
};
@@ -2741,13 +1612,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
- // The panic_no_unwind function called by TerminatorKind::Abort will never
- // unwind. If the panic handler that it invokes unwind then it will simply
- // call the panic handler again.
- if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
-
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;
@@ -2808,7 +1672,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
)
.emit();
}
- } else if attr.has_name(sym::rustc_allocator_nounwind) {
+ } else if attr.has_name(sym::rustc_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} else if attr.has_name(sym::rustc_reallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
@@ -3154,6 +2018,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
E0535,
"invalid argument"
)
+ .help("valid inline arguments are `always` and `never`")
.emit();
InlineAttr::None
@@ -3227,11 +2092,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
- |lint| {
- lint.build("`no_sanitize` will have no effect after inlining")
- .span_note(inline_span, "inlining requested here")
- .emit();
- },
+ "`no_sanitize` will have no effect after inlining",
+ |lint| lint.span_note(inline_span, "inlining requested here"),
)
}
}
@@ -3386,7 +2248,7 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
let parent_id = tcx.hir().get_parent_item(hir_id);
- let parent_item = tcx.hir().expect_item(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_id.def_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
.struct_span_err(
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
new file mode 100644
index 000000000..c7777a946
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -0,0 +1,481 @@
+use crate::middle::resolve_lifetime as rl;
+use hir::{
+ intravisit::{self, Visitor},
+ GenericParamKind, HirId, Node,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint;
+use rustc_span::symbol::{kw, Symbol};
+use rustc_span::Span;
+
+pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
+ use rustc_hir::*;
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+ let node = tcx.hir().get(hir_id);
+ let parent_def_id = match node {
+ Node::ImplItem(_)
+ | Node::TraitItem(_)
+ | Node::Variant(_)
+ | Node::Ctor(..)
+ | Node::Field(_) => {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ Some(parent_id.to_def_id())
+ }
+ // FIXME(#43408) always enable this once `lazy_normalization` is
+ // stable enough and does not need a feature gate anymore.
+ Node::AnonConst(_) => {
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
+ let mut in_param_ty = false;
+ for (_parent, node) in tcx.hir().parent_iter(hir_id) {
+ if let Some(generics) = node.generics() {
+ let mut visitor = AnonConstInParamTyDetector {
+ in_param_ty: false,
+ found_anon_const_in_param_ty: false,
+ ct: hir_id,
+ };
+
+ visitor.visit_generics(generics);
+ in_param_ty = visitor.found_anon_const_in_param_ty;
+ break;
+ }
+ }
+
+ if in_param_ty {
+ // We do not allow generic parameters in anon consts if we are inside
+ // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
+ None
+ } else if tcx.lazy_normalization() {
+ if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ // If the def_id we are calling generics_of on is an anon ct default i.e:
+ //
+ // struct Foo<const N: usize = { .. }>;
+ // ^^^ ^ ^^^^^^ def id of this anon const
+ // ^ ^ param_id
+ // ^ parent_def_id
+ //
+ // then we only want to return generics for params to the left of `N`. If we don't do that we
+ // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+ //
+ // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+ // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+ // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+ //
+ // We fix this by having this function return the parent's generics ourselves and truncating the
+ // generics to only include non-forward declared params (with the exception of the `Self` ty)
+ //
+ // For the above code example that means we want `substs: []`
+ // For the following struct def we want `substs: [N#0]` when generics_of is called on
+ // the def id of the `{ N + 1 }` anon const
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ //
+ // This has some implications for how we get the predicates available to the anon const
+ // see `explicit_predicates_of` for more information on this
+ let generics = tcx.generics_of(parent_def_id.to_def_id());
+ let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+ let param_def_idx = generics.param_def_id_to_index[&param_def];
+ // In the above example this would be .params[..N#0]
+ let params = generics.params[..param_def_idx as usize].to_owned();
+ let param_def_id_to_index =
+ params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ return ty::Generics {
+ // we set the parent of these generics to be our parent's parent so that we
+ // dont end up with substs: [N, M, N] for the const default on a struct like this:
+ // struct Foo<const N: usize, const M: usize = { ... }>;
+ parent: generics.parent,
+ parent_count: generics.parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: generics.has_self,
+ has_late_bound_regions: generics.has_late_bound_regions,
+ };
+ }
+
+ // HACK(eddyb) this provides the correct generics when
+ // `feature(generic_const_expressions)` is enabled, so that const expressions
+ // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+ //
+ // Note that we do not supply the parent generics when using
+ // `min_const_generics`.
+ Some(parent_def_id.to_def_id())
+ } else {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ match parent_node {
+ // HACK(eddyb) this provides the correct generics for repeat
+ // expressions' count (i.e. `N` in `[x; N]`), and explicit
+ // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
+ // as they shouldn't be able to cause query cycle errors.
+ Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+ if constant.hir_id() == hir_id =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+ if constant.hir_id == hir_id =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
+ // Exclude `GlobalAsm` here which cannot have generics.
+ Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+ if asm.operands.iter().any(|(op, _op_sp)| match op {
+ hir::InlineAsmOperand::Const { anon_const }
+ | hir::InlineAsmOperand::SymFn { anon_const } => {
+ anon_const.hir_id == hir_id
+ }
+ _ => false,
+ }) =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ _ => None,
+ }
+ }
+ }
+ Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
+ Node::Item(item) => match item.kind {
+ ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin:
+ hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ in_trait,
+ ..
+ }) => {
+ if in_trait {
+ assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+ } else {
+ assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+ }
+ Some(fn_def_id.to_def_id())
+ }
+ ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+ let parent_id = tcx.hir().get_parent_item(hir_id);
+ assert_ne!(parent_id, hir::CRATE_OWNER_ID);
+ debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
+ // Opaque types are always nested within another item, and
+ // inherit the generics of the item.
+ Some(parent_id.to_def_id())
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+
+ enum Defaults {
+ Allowed,
+ // See #36887
+ FutureCompatDisallowed,
+ Deny,
+ }
+
+ let no_generics = hir::Generics::empty();
+ let ast_generics = node.generics().unwrap_or(&no_generics);
+ let (opt_self, allow_defaults) = match node {
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
+ // Add in the self type parameter.
+ //
+ // Something of a hack: use the node id for the trait, also as
+ // the node id for the Self type parameter.
+ let opt_self = Some(ty::GenericParamDef {
+ index: 0,
+ name: kw::SelfUpper,
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ synthetic: false,
+ },
+ });
+
+ (opt_self, Defaults::Allowed)
+ }
+ ItemKind::TyAlias(..)
+ | ItemKind::Enum(..)
+ | ItemKind::Struct(..)
+ | ItemKind::OpaqueTy(..)
+ | ItemKind::Union(..) => (None, Defaults::Allowed),
+ _ => (None, Defaults::FutureCompatDisallowed),
+ }
+ }
+
+ // GATs
+ Node::TraitItem(item) if matches!(item.kind, TraitItemKind::Type(..)) => {
+ (None, Defaults::Deny)
+ }
+ Node::ImplItem(item) if matches!(item.kind, ImplItemKind::Type(..)) => {
+ (None, Defaults::Deny)
+ }
+
+ _ => (None, Defaults::FutureCompatDisallowed),
+ };
+
+ let has_self = opt_self.is_some();
+ let mut parent_has_self = false;
+ let mut own_start = has_self as u32;
+ let parent_count = parent_def_id.map_or(0, |def_id| {
+ let generics = tcx.generics_of(def_id);
+ assert!(!has_self);
+ parent_has_self = generics.has_self;
+ own_start = generics.count() as u32;
+ generics.parent_count + generics.params.len()
+ });
+
+ let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+
+ if let Some(opt_self) = opt_self {
+ params.push(opt_self);
+ }
+
+ let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics);
+ params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
+ name: param.name.ident().name,
+ index: own_start + i as u32,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind: ty::GenericParamDefKind::Lifetime,
+ }));
+
+ // Now create the real type and const parameters.
+ let type_start = own_start - has_self as u32 + params.len() as u32;
+ let mut i = 0;
+ let mut next_index = || {
+ let prev = i;
+ i += 1;
+ prev as u32 + type_start
+ };
+
+ const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
+ `struct`, `enum`, `type`, or `trait` definitions";
+
+ params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+ GenericParamKind::Lifetime { .. } => None,
+ GenericParamKind::Type { ref default, synthetic, .. } => {
+ if default.is_some() {
+ match allow_defaults {
+ Defaults::Allowed => {}
+ Defaults::FutureCompatDisallowed
+ if tcx.features().default_type_parameter_fallback => {}
+ Defaults::FutureCompatDisallowed => {
+ tcx.struct_span_lint_hir(
+ lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+ param.hir_id,
+ param.span,
+ TYPE_DEFAULT_NOT_ALLOWED,
+ |lint| lint,
+ );
+ }
+ Defaults::Deny => {
+ tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+ }
+ }
+ }
+
+ let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
+
+ Some(ty::GenericParamDef {
+ index: next_index(),
+ name: param.name.ident().name,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind,
+ })
+ }
+ GenericParamKind::Const { default, .. } => {
+ if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
+ tcx.sess.span_err(
+ param.span,
+ "defaults for const parameters are only allowed in \
+ `struct`, `enum`, `type`, or `trait` definitions",
+ );
+ }
+
+ Some(ty::GenericParamDef {
+ index: next_index(),
+ name: param.name.ident().name,
+ def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ pure_wrt_drop: param.pure_wrt_drop,
+ kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+ })
+ }
+ }));
+
+ // provide junk type parameter defs - the only place that
+ // cares about anything but the length is instantiation,
+ // and we don't do that for closures.
+ if let Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }),
+ ..
+ }) = node
+ {
+ let dummy_args = if gen.is_some() {
+ &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
+ } else {
+ &["<closure_kind>", "<closure_signature>", "<upvars>"][..]
+ };
+
+ params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
+ index: next_index(),
+ name: Symbol::intern(arg),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+ }));
+ }
+
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: next_index(),
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
+ });
+ }
+ }
+
+ let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ ty::Generics {
+ parent: parent_def_id,
+ parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: has_self || parent_has_self,
+ has_late_bound_regions: has_late_bound_regions(tcx, node),
+ }
+}
+
+fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<Span> {
+ struct LateBoundRegionsDetector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ outer_index: ty::DebruijnIndex,
+ has_late_bound_regions: Option<Span>,
+ }
+
+ impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
+ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+ match ty.kind {
+ hir::TyKind::BareFn(..) => {
+ self.outer_index.shift_in(1);
+ intravisit::walk_ty(self, ty);
+ self.outer_index.shift_out(1);
+ }
+ _ => intravisit::walk_ty(self, ty),
+ }
+ }
+
+ fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+ self.outer_index.shift_in(1);
+ intravisit::walk_poly_trait_ref(self, tr);
+ self.outer_index.shift_out(1);
+ }
+
+ fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
+ if self.has_late_bound_regions.is_some() {
+ return;
+ }
+
+ match self.tcx.named_region(lt.hir_id) {
+ Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
+ Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
+ Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
+ self.has_late_bound_regions = Some(lt.span);
+ }
+ }
+ }
+ }
+
+ fn has_late_bound_regions<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx hir::Generics<'tcx>,
+ decl: &'tcx hir::FnDecl<'tcx>,
+ ) -> Option<Span> {
+ let mut visitor = LateBoundRegionsDetector {
+ tcx,
+ outer_index: ty::INNERMOST,
+ has_late_bound_regions: None,
+ };
+ for param in generics.params {
+ if let GenericParamKind::Lifetime { .. } = param.kind {
+ if tcx.is_late_bound(param.hir_id) {
+ return Some(param.span);
+ }
+ }
+ }
+ visitor.visit_fn_decl(decl);
+ visitor.has_late_bound_regions
+ }
+
+ match node {
+ Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Fn(ref sig, _) => {
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
+ }
+ _ => None,
+ },
+ Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::Fn(ref sig, _) => {
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
+ }
+ _ => None,
+ },
+ Node::ForeignItem(item) => match item.kind {
+ hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
+ has_late_bound_regions(tcx, generics, fn_decl)
+ }
+ _ => None,
+ },
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
+ has_late_bound_regions(tcx, generics, sig.decl)
+ }
+ _ => None,
+ },
+ _ => None,
+ }
+}
+
+struct AnonConstInParamTyDetector {
+ in_param_ty: bool,
+ found_anon_const_in_param_ty: bool,
+ ct: HirId,
+}
+
+impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
+ fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
+ if let GenericParamKind::Const { ty, default: _ } = p.kind {
+ let prev = self.in_param_ty;
+ self.in_param_ty = true;
+ self.visit_ty(ty);
+ self.in_param_ty = prev;
+ }
+ }
+
+ fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
+ if self.in_param_ty && self.ct == c.hir_id {
+ self.found_anon_const_in_param_ty = true;
+ } else {
+ intravisit::walk_anon_const(self, c)
+ }
+ }
+}
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 0d34a8bfe..0d34a8bfe 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 4d9704617..3f263a6de 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -32,8 +32,6 @@ trait RegionExt {
fn id(&self) -> Option<DefId>;
fn shifted(self, amount: u32) -> Region;
-
- fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region;
}
impl RegionExt for Region {
@@ -69,15 +67,6 @@ impl RegionExt for Region {
_ => self,
}
}
-
- fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
- match self {
- Region::LateBound(debruijn, index, id) => {
- Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id)
- }
- _ => self,
- }
- }
}
/// Maps the id of each lifetime reference to the lifetime decl
@@ -101,8 +90,8 @@ struct NamedRegionMap {
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
}
-pub(crate) struct LifetimeContext<'a, 'tcx> {
- pub(crate) tcx: TyCtxt<'tcx>,
+struct LifetimeContext<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
@@ -234,7 +223,7 @@ type ScopeRef<'a> = &'a Scope<'a>;
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
-pub fn provide(providers: &mut ty::query::Providers) {
+pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
resolve_lifetimes_trait_definition,
resolve_lifetimes,
@@ -326,6 +315,7 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
}
debug!(?rl.defs);
+ debug!(?rl.late_bound_vars);
rl
}
@@ -339,24 +329,25 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
/// other than the trait itself (like the trait methods or associated types), then we just use the regular
/// `resolve_lifetimes`.
-fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes {
- let item_id = item_for(tcx, def_id);
- if item_id == def_id {
- let item = tcx.hir().item(hir::ItemId { def_id: item_id });
+fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
+ let item_id = item_for(tcx, def_id.def_id);
+ let local_def_id = item_id.owner_id.def_id;
+ if item_id.owner_id == def_id {
+ let item = tcx.hir().item(item_id);
match item.kind {
- hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(item_id),
- _ => tcx.resolve_lifetimes(item_id),
+ hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
+ _ => tcx.resolve_lifetimes(local_def_id),
}
} else {
- tcx.resolve_lifetimes(item_id)
+ tcx.resolve_lifetimes(local_def_id)
}
}
/// Finds the `Item` that contains the given `LocalDefId`
-fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
+fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
match tcx.hir().find_by_def_id(local_def_id) {
Some(Node::Item(item)) => {
- return item.def_id;
+ return item.item_id();
}
_ => {}
}
@@ -366,7 +357,7 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
loop {
let node = parent_iter.next().map(|n| n.1);
match node {
- Some(hir::Node::Item(item)) => break item.def_id,
+ Some(hir::Node::Item(item)) => break item.item_id(),
Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
_ => {}
}
@@ -506,7 +497,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.unzip();
- self.map.late_bound_vars.insert(e.hir_id, binders);
+ self.record_late_bound_vars(e.hir_id, binders);
let scope = Scope::Binder {
hir_id: e.hir_id,
lifetimes,
@@ -530,7 +521,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
match &item.kind {
hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
if let Some(of_trait) = of_trait {
- self.map.late_bound_vars.insert(of_trait.hir_ref_id, Vec::default());
+ self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
}
}
_ => {}
@@ -566,13 +557,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// their owner, we can keep going until we find the Item that owns that. We then
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
- for (_hir_id, node) in
- self.tcx.hir().parent_iter(self.tcx.hir().local_def_id_to_hir_id(item.def_id))
- {
+ for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
match node {
hir::Node::Item(parent_item) => {
- let resolved_lifetimes: &ResolveLifetimes =
- self.tcx.resolve_lifetimes(item_for(self.tcx, parent_item.def_id));
+ let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
+ item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
+ );
// We need to add *all* deps, since opaque tys may want them from *us*
for (&owner, defs) in resolved_lifetimes.defs.iter() {
defs.iter().for_each(|(&local_id, region)| {
@@ -583,7 +573,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
resolved_lifetimes.late_bound_vars.iter()
{
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
- self.map.late_bound_vars.insert(
+ self.record_late_bound_vars(
hir::HirId { owner, local_id },
late_bound_vars.clone(),
);
@@ -614,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(item.hir_id(), vec![]);
+ self.record_late_bound_vars(item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: item.hir_id(),
lifetimes,
@@ -663,7 +653,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
(pair, r)
})
.unzip();
- self.map.late_bound_vars.insert(ty.hir_id, binders);
+ self.record_late_bound_vars(ty.hir_id, binders);
let scope = Scope::Binder {
hir_id: ty.hir_id,
lifetimes,
@@ -817,7 +807,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
}
}
- self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+ self.record_late_bound_vars(ty.hir_id, vec![]);
let scope = Scope::Binder {
hir_id: ty.hir_id,
@@ -861,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
+ self.record_late_bound_vars(trait_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: trait_item.hir_id(),
lifetimes,
@@ -897,7 +887,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
intravisit::walk_impl_item(this, impl_item)
}),
- TyAlias(ref ty) => {
+ Type(ref ty) => {
let generics = &impl_item.generics;
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
@@ -909,9 +899,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
})
.collect();
- self.map.late_bound_vars.insert(ty.hir_id, vec![]);
+ self.record_late_bound_vars(impl_item.hir_id(), vec![]);
let scope = Scope::Binder {
- hir_id: ty.hir_id,
+ hir_id: impl_item.hir_id(),
lifetimes,
s: self.scope,
scope_type: BinderScopeType::Normal,
@@ -995,13 +985,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
for predicate in generics.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id,
ref bounded_ty,
bounds,
ref bound_generic_params,
origin,
..
}) => {
- let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+ let lifetimes: FxIndexMap<LocalDefId, Region> =
bound_generic_params
.iter()
.filter(|param| {
@@ -1009,19 +1000,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
})
.enumerate()
.map(|(late_bound_idx, param)| {
- let pair =
- Region::late(late_bound_idx as u32, this.tcx.hir(), param);
- let r = late_region_as_bound_region(this.tcx, &pair.1);
- (pair, r)
+ Region::late(late_bound_idx as u32, this.tcx.hir(), param)
+ })
+ .collect();
+ let binders: Vec<_> =
+ lifetimes
+ .iter()
+ .map(|(_, region)| {
+ late_region_as_bound_region(this.tcx, region)
})
- .unzip();
- this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
+ .collect();
+ this.record_late_bound_vars(hir_id, binders.clone());
// Even if there are no lifetimes defined here, we still wrap it in a binder
// scope. If there happens to be a nested poly trait ref (an error), that
// will be `Concatenating` anyways, so we don't have to worry about the depth
// being wrong.
let scope = Scope::Binder {
- hir_id: bounded_ty.hir_id,
+ hir_id,
lifetimes,
s: this.scope,
scope_type: BinderScopeType::Normal,
@@ -1089,7 +1084,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// imagine there's a better way to go about this.
let (binders, scope_type) = self.poly_trait_ref_binder_info();
- self.map.late_bound_vars.insert(*hir_id, binders);
+ self.record_late_bound_vars(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
lifetimes: FxIndexMap::default(),
@@ -1127,7 +1122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
binders.extend(binders_iter);
debug!(?binders);
- self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders);
+ self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
// Always introduce a scope here, even if this is in a where clause and
// we introduced the binders around the bounded Ty. In that case, we
@@ -1211,6 +1206,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
+ fn record_late_bound_vars(&mut self, hir_id: hir::HirId, binder: Vec<ty::BoundVariableKind>) {
+ if let Some(old) = self.map.late_bound_vars.insert(hir_id, binder) {
+ bug!(
+ "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
+ self.map.late_bound_vars[&hir_id]
+ )
+ }
+ }
+
/// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
///
/// Handles visiting fns and methods. These are a bit complicated because we must distinguish
@@ -1268,7 +1272,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
- self.map.late_bound_vars.insert(hir_id, binders);
+ self.record_late_bound_vars(hir_id, binders);
let scope = Scope::Binder {
hir_id,
lifetimes,
@@ -1315,15 +1319,44 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(_, hir::ParamName::Fresh) = lifetime_ref.name
- && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner)
+ && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
- rustc_session::parse::feature_err(
+ let mut diag = rustc_session::parse::feature_err(
&self.tcx.sess.parse_sess,
sym::anonymous_lifetime_in_impl_trait,
lifetime_ref.span,
"anonymous lifetimes in `impl Trait` are unstable",
- ).emit();
+ );
+
+ match self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) {
+ Some(generics) => {
+
+ let new_param_sugg_tuple;
+
+ new_param_sugg_tuple = match generics.span_for_param_suggestion() {
+ Some(_) => {
+ Some((self.tcx.sess.source_map().span_through_char(generics.span, '<').shrink_to_hi(), "'a, ".to_owned()))
+ },
+ None => Some((generics.span, "<'a>".to_owned()))
+ };
+
+ let mut multi_sugg_vec = vec![(lifetime_ref.span.shrink_to_hi(), "'a ".to_owned())];
+
+ if let Some(new_tuple) = new_param_sugg_tuple{
+ multi_sugg_vec.push(new_tuple);
+ }
+
+ diag.span_label(lifetime_ref.span, "expected named lifetime parameter");
+ diag.multipart_suggestion("consider introducing a named lifetime parameter",
+ multi_sugg_vec,
+ rustc_errors::Applicability::MaybeIncorrect);
+
+ },
+ None => { }
+ }
+
+ diag.emit();
return;
}
scope = s;
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
new file mode 100644
index 000000000..2e84e1d01
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -0,0 +1,707 @@
+use crate::astconv::AstConv;
+use crate::bounds::Bounds;
+use crate::collect::ItemCtxt;
+use crate::constrained_generic_params as cgp;
+use hir::{HirId, Node};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{Span, DUMMY_SP};
+
+#[derive(Debug)]
+struct OnlySelfBounds(bool);
+
+/// Returns a list of all type predicates (explicit and implicit) for the definition with
+/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
+/// `Self: Trait` predicates for traits.
+pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+ let mut result = tcx.predicates_defined_on(def_id);
+
+ if tcx.is_trait(def_id) {
+ // For traits, add `Self: Trait` predicate. This is
+ // not part of the predicates that a user writes, but it
+ // is something that one must prove in order to invoke a
+ // method or project an associated type.
+ //
+ // In the chalk setup, this predicate is not part of the
+ // "predicates" for a trait item. But it is useful in
+ // rustc because if you directly (e.g.) invoke a trait
+ // method like `Trait::method(...)`, you must naturally
+ // prove that the trait applies to the types that were
+ // used, and adding the predicate into this list ensures
+ // that this is done.
+ //
+ // We use a DUMMY_SP here as a way to signal trait bounds that come
+ // from the trait itself that *shouldn't* be shown as the source of
+ // an obligation and instead be skipped. Otherwise we'd use
+ // `tcx.def_span(def_id);`
+
+ let constness = if tcx.has_attr(def_id, sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
+
+ let span = rustc_span::DUMMY_SP;
+ result.predicates =
+ tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
+ ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
+ span,
+ ))));
+ }
+ debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
+ result
+}
+
+/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
+/// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
+fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+ use rustc_hir::*;
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let node = tcx.hir().get(hir_id);
+
+ let mut is_trait = None;
+ let mut is_default_impl_trait = None;
+
+ let icx = ItemCtxt::new(tcx, def_id);
+
+ const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
+
+ // We use an `IndexSet` to preserves order of insertion.
+ // Preserving the order of insertion is important here so as not to break UI tests.
+ let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+
+ let ast_generics = match node {
+ Node::TraitItem(item) => item.generics,
+
+ Node::ImplItem(item) => item.generics,
+
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Impl(ref impl_) => {
+ if impl_.defaultness.is_default() {
+ is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy);
+ }
+ &impl_.generics
+ }
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => *generics,
+
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::TraitAlias(ref generics, _) => {
+ is_trait = Some(ty::TraitRef::identity(tcx, def_id));
+ *generics
+ }
+ ItemKind::OpaqueTy(OpaqueTy {
+ origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+ ..
+ }) => {
+ // return-position impl trait
+ //
+ // We don't inherit predicates from the parent here:
+ // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+ // then the return type is `f::<'static, T>::{{opaque}}`.
+ //
+ // If we inherited the predicates of `f` then we would
+ // require that `T: 'static` to show that the return
+ // type is well-formed.
+ //
+ // The only way to have something with this opaque type
+ // is from the return type of the containing function,
+ // which will ensure that the function's predicates
+ // hold.
+ return ty::GenericPredicates { parent: None, predicates: &[] };
+ }
+ ItemKind::OpaqueTy(OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ }) => {
+ // type-alias impl trait
+ generics
+ }
+
+ _ => NO_GENERICS,
+ }
+ }
+
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Static(..) => NO_GENERICS,
+ ForeignItemKind::Fn(_, _, ref generics) => *generics,
+ ForeignItemKind::Type => NO_GENERICS,
+ },
+
+ _ => NO_GENERICS,
+ };
+
+ let generics = tcx.generics_of(def_id);
+ let parent_count = generics.parent_count as u32;
+ let has_own_self = generics.has_self && parent_count == 0;
+
+ // Below we'll consider the bounds on the type parameters (including `Self`)
+ // and the explicit where-clauses, but to get the full set of predicates
+ // on a trait we need to add in the supertrait bounds and bounds found on
+ // associated types.
+ if let Some(_trait_ref) = is_trait {
+ predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
+ }
+
+ // In default impls, we can assume that the self type implements
+ // the trait. So in:
+ //
+ // default impl Foo for Bar { .. }
+ //
+ // we add a default where clause `Foo: Bar`. We do a similar thing for traits
+ // (see below). Recall that a default impl is not itself an impl, but rather a
+ // set of defaults that can be incorporated into another impl.
+ if let Some(trait_ref) = is_default_impl_trait {
+ predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
+ }
+
+ // Collect the region predicates that were declared inline as
+ // well. In the case of parameters declared on a fn or method, we
+ // have to be careful to only iterate over early-bound regions.
+ let mut index = parent_count
+ + has_own_self as u32
+ + super::early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
+
+ trace!(?predicates);
+ trace!(?ast_generics);
+
+ // Collect the predicates that were written inline by the user on each
+ // type parameter (e.g., `<T: Foo>`).
+ for param in ast_generics.params {
+ match param.kind {
+ // We already dealt with early bound lifetimes above.
+ GenericParamKind::Lifetime { .. } => (),
+ GenericParamKind::Type { .. } => {
+ let name = param.name.ident().name;
+ let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+ index += 1;
+
+ let mut bounds = Bounds::default();
+ // Params are implicitly sized unless a `?Sized` bound is found
+ <dyn AstConv<'_>>::add_implicitly_sized(
+ &icx,
+ &mut bounds,
+ &[],
+ Some((param.hir_id, ast_generics.predicates)),
+ param.span,
+ );
+ trace!(?bounds);
+ predicates.extend(bounds.predicates(tcx, param_ty));
+ trace!(?predicates);
+ }
+ GenericParamKind::Const { .. } => {
+ // Bounds on const parameters are currently not possible.
+ index += 1;
+ }
+ }
+ }
+
+ trace!(?predicates);
+ // Add in the bounds that appear in the where-clause.
+ for predicate in ast_generics.predicates {
+ match predicate {
+ hir::WherePredicate::BoundPredicate(bound_pred) => {
+ let ty = icx.to_ty(bound_pred.bounded_ty);
+ let bound_vars = icx.tcx.late_bound_vars(bound_pred.hir_id);
+
+ // Keep the type around in a dummy predicate, in case of no bounds.
+ // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
+ // is still checked for WF.
+ if bound_pred.bounds.is_empty() {
+ if let ty::Param(_) = ty.kind() {
+ // This is a `where T:`, which can be in the HIR from the
+ // transformation that moves `?Sized` to `T`'s declaration.
+ // We can skip the predicate because type parameters are
+ // trivially WF, but also we *should*, to avoid exposing
+ // users who never wrote `where Type:,` themselves, to
+ // compiler/tooling bugs from not handling WF predicates.
+ } else {
+ let span = bound_pred.bounded_ty.span;
+ let predicate = ty::Binder::bind_with_vars(
+ ty::PredicateKind::WellFormed(ty.into()),
+ bound_vars,
+ );
+ predicates.insert((predicate.to_predicate(tcx), span));
+ }
+ }
+
+ let mut bounds = Bounds::default();
+ <dyn AstConv<'_>>::add_bounds(
+ &icx,
+ ty,
+ bound_pred.bounds.iter(),
+ &mut bounds,
+ bound_vars,
+ );
+ predicates.extend(bounds.predicates(tcx, ty));
+ }
+
+ hir::WherePredicate::RegionPredicate(region_pred) => {
+ let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+ predicates.extend(region_pred.bounds.iter().map(|bound| {
+ let (r2, span) = match bound {
+ hir::GenericBound::Outlives(lt) => {
+ (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.span)
+ }
+ _ => bug!(),
+ };
+ let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+ ty::OutlivesPredicate(r1, r2),
+ ))
+ .to_predicate(icx.tcx);
+
+ (pred, span)
+ }))
+ }
+
+ hir::WherePredicate::EqPredicate(..) => {
+ // FIXME(#20041)
+ }
+ }
+ }
+
+ if tcx.features().generic_const_exprs {
+ predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
+ }
+
+ let mut predicates: Vec<_> = predicates.into_iter().collect();
+
+ // Subtle: before we store the predicates into the tcx, we
+ // sort them so that predicates like `T: Foo<Item=U>` come
+ // before uses of `U`. This avoids false ambiguity errors
+ // in trait checking. See `setup_constraining_predicates`
+ // for details.
+ if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
+ let self_ty = tcx.type_of(def_id);
+ let trait_ref = tcx.impl_trait_ref(def_id);
+ cgp::setup_constraining_predicates(
+ tcx,
+ &mut predicates,
+ trait_ref,
+ &mut cgp::parameters_for_impl(self_ty, trait_ref),
+ );
+ }
+
+ ty::GenericPredicates {
+ parent: generics.parent,
+ predicates: tcx.arena.alloc_from_iter(predicates),
+ }
+}
+
+fn const_evaluatable_predicates_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> {
+ struct ConstCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+ }
+
+ impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
+ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
+ let def_id = self.tcx.hir().local_def_id(c.hir_id);
+ let ct = ty::Const::from_anon_const(self.tcx, def_id);
+ if let ty::ConstKind::Unevaluated(_) = ct.kind() {
+ let span = self.tcx.hir().span(c.hir_id);
+ self.preds.insert((
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
+ .to_predicate(self.tcx),
+ span,
+ ));
+ }
+ }
+
+ fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
+ // Do not look into const param defaults,
+ // these get checked when they are actually instantiated.
+ //
+ // We do not want the following to error:
+ //
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ // struct Bar<const N: usize>(Foo<N, 3>);
+ }
+ }
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let node = tcx.hir().get(hir_id);
+
+ let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
+ if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind {
+ if let Some(of_trait) = &impl_.of_trait {
+ debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
+ collector.visit_trait_ref(of_trait);
+ }
+
+ debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
+ collector.visit_ty(impl_.self_ty);
+ }
+
+ if let Some(generics) = node.generics() {
+ debug!("const_evaluatable_predicates_of({:?}): visit_generics", def_id);
+ collector.visit_generics(generics);
+ }
+
+ if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) {
+ debug!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id);
+ collector.visit_fn_decl(fn_sig.decl);
+ }
+ debug!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds);
+
+ collector.preds
+}
+
+pub(super) fn trait_explicit_predicates_and_bounds(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+) -> ty::GenericPredicates<'_> {
+ assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
+ gather_explicit_predicates_of(tcx, def_id.to_def_id())
+}
+
+pub(super) fn explicit_predicates_of<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> ty::GenericPredicates<'tcx> {
+ let def_kind = tcx.def_kind(def_id);
+ if let DefKind::Trait = def_kind {
+ // Remove bounds on associated types from the predicates, they will be
+ // returned by `explicit_item_bounds`.
+ let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
+ let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
+
+ let is_assoc_item_ty = |ty: Ty<'tcx>| {
+ // For a predicate from a where clause to become a bound on an
+ // associated type:
+ // * It must use the identity substs of the item.
+ // * Since any generic parameters on the item are not in scope,
+ // this means that the item is not a GAT, and its identity
+ // substs are the same as the trait's.
+ // * It must be an associated type for this trait (*not* a
+ // supertrait).
+ if let ty::Projection(projection) = ty.kind() {
+ projection.substs == trait_identity_substs
+ && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
+ } else {
+ false
+ }
+ };
+
+ let predicates: Vec<_> = predicates_and_bounds
+ .predicates
+ .iter()
+ .copied()
+ .filter(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Projection(proj) => {
+ !is_assoc_item_ty(proj.projection_ty.self_ty())
+ }
+ ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+ _ => true,
+ })
+ .collect();
+ if predicates.len() == predicates_and_bounds.predicates.len() {
+ predicates_and_bounds
+ } else {
+ ty::GenericPredicates {
+ parent: predicates_and_bounds.parent,
+ predicates: tcx.arena.alloc_slice(&predicates),
+ }
+ }
+ } else {
+ if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+ // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // ^^^ explicit_predicates_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`
+ let item_def_id = tcx.hir().get_parent_item(hir_id);
+ // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(item_def_id);
+ }
+ }
+ gather_explicit_predicates_of(tcx, def_id)
+ }
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_of(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+) -> ty::GenericPredicates<'_> {
+ tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+}
+
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+pub(super) fn super_predicates_that_define_assoc_type(
+ tcx: TyCtxt<'_>,
+ (trait_def_id, assoc_name): (DefId, Option<Ident>),
+) -> ty::GenericPredicates<'_> {
+ if trait_def_id.is_local() {
+ debug!("local trait");
+ let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+
+ let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
+ bug!("trait_node_id {} is not an item", trait_hir_id);
+ };
+
+ let (generics, bounds) = match item.kind {
+ hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+ hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+ _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+ };
+
+ let icx = ItemCtxt::new(tcx, trait_def_id);
+
+ // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+ let self_param_ty = tcx.types.self_param;
+ let superbounds1 = if let Some(assoc_name) = assoc_name {
+ <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
+ &icx,
+ self_param_ty,
+ bounds,
+ assoc_name,
+ )
+ } else {
+ <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+ };
+
+ let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+ // Convert any explicit superbounds in the where-clause,
+ // e.g., `trait Foo where Self: Bar`.
+ // In the case of trait aliases, however, we include all bounds in the where-clause,
+ // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+ // as one of its "superpredicates".
+ let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+ let superbounds2 = icx.type_parameter_bounds_in_generics(
+ generics,
+ item.hir_id(),
+ self_param_ty,
+ OnlySelfBounds(!is_trait_alias),
+ assoc_name,
+ );
+
+ // Combine the two lists to form the complete set of superbounds:
+ let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+ debug!(?superbounds);
+
+ // Now require that immediate supertraits are converted,
+ // which will, in turn, reach indirect supertraits.
+ if assoc_name.is_none() {
+ // Now require that immediate supertraits are converted,
+ // which will, in turn, reach indirect supertraits.
+ for &(pred, span) in superbounds {
+ debug!("superbound: {:?}", pred);
+ if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
+ tcx.at(span).super_predicates_of(bound.def_id());
+ }
+ }
+ }
+
+ ty::GenericPredicates { parent: None, predicates: superbounds }
+ } else {
+ // if `assoc_name` is None, then the query should've been redirected to an
+ // external provider
+ assert!(assoc_name.is_some());
+ tcx.super_predicates_of(trait_def_id)
+ }
+}
+
+/// Returns the predicates defined on `item_def_id` of the form
+/// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
+pub(super) fn type_param_predicates(
+ tcx: TyCtxt<'_>,
+ (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
+) -> ty::GenericPredicates<'_> {
+ use rustc_hir::*;
+
+ // In the AST, bounds can derive from two places. Either
+ // written inline like `<T: Foo>` or in a where-clause like
+ // `where T: Foo`.
+
+ let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let param_owner = tcx.hir().ty_param_owner(def_id);
+ let generics = tcx.generics_of(param_owner);
+ let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+ let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+
+ // Don't look for bounds where the type parameter isn't in scope.
+ let parent = if item_def_id == param_owner.to_def_id() {
+ None
+ } else {
+ tcx.generics_of(item_def_id).parent
+ };
+
+ let mut result = parent
+ .map(|parent| {
+ let icx = ItemCtxt::new(tcx, parent);
+ icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
+ })
+ .unwrap_or_default();
+ let mut extend = None;
+
+ let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+ let ast_generics = match tcx.hir().get(item_hir_id) {
+ Node::TraitItem(item) => &item.generics,
+
+ Node::ImplItem(item) => &item.generics,
+
+ Node::Item(item) => {
+ match item.kind {
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::Impl(hir::Impl { ref generics, .. })
+ | ItemKind::TyAlias(_, ref generics)
+ | ItemKind::OpaqueTy(OpaqueTy {
+ ref generics,
+ origin: hir::OpaqueTyOrigin::TyAlias,
+ ..
+ })
+ | ItemKind::Enum(_, ref generics)
+ | ItemKind::Struct(_, ref generics)
+ | ItemKind::Union(_, ref generics) => generics,
+ ItemKind::Trait(_, _, ref generics, ..) => {
+ // Implied `Self: Trait` and supertrait bounds.
+ if param_id == item_hir_id {
+ let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
+ extend =
+ Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
+ }
+ generics
+ }
+ _ => return result,
+ }
+ }
+
+ Node::ForeignItem(item) => match item.kind {
+ ForeignItemKind::Fn(_, _, ref generics) => generics,
+ _ => return result,
+ },
+
+ _ => return result,
+ };
+
+ let icx = ItemCtxt::new(tcx, item_def_id);
+ let extra_predicates = extend.into_iter().chain(
+ icx.type_parameter_bounds_in_generics(
+ ast_generics,
+ param_id,
+ ty,
+ OnlySelfBounds(true),
+ Some(assoc_name),
+ )
+ .into_iter()
+ .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
+ _ => false,
+ }),
+ );
+ result.predicates =
+ tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
+ result
+}
+
+impl<'tcx> ItemCtxt<'tcx> {
+ /// Finds bounds from `hir::Generics`. This requires scanning through the
+ /// AST. We do this to avoid having to convert *all* the bounds, which
+ /// would create artificial cycles. Instead, we can only convert the
+ /// bounds for a type parameter `X` if `X::Foo` is used.
+ #[instrument(level = "trace", skip(self, ast_generics))]
+ fn type_parameter_bounds_in_generics(
+ &self,
+ ast_generics: &'tcx hir::Generics<'tcx>,
+ param_id: hir::HirId,
+ ty: Ty<'tcx>,
+ only_self_bounds: OnlySelfBounds,
+ assoc_name: Option<Ident>,
+ ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+ let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+ trace!(?param_def_id);
+ ast_generics
+ .predicates
+ .iter()
+ .filter_map(|wp| match *wp {
+ hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
+ _ => None,
+ })
+ .flat_map(|bp| {
+ let bt = if bp.is_param_bound(param_def_id) {
+ Some(ty)
+ } else if !only_self_bounds.0 {
+ Some(self.to_ty(bp.bounded_ty))
+ } else {
+ None
+ };
+ let bvars = self.tcx.late_bound_vars(bp.hir_id);
+
+ bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
+ |(_, b, _)| match assoc_name {
+ Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
+ None => true,
+ },
+ )
+ })
+ .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
+ .collect()
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
+ match b {
+ hir::GenericBound::Trait(poly_trait_ref, _) => {
+ let trait_ref = &poly_trait_ref.trait_ref;
+ if let Some(trait_did) = trait_ref.trait_def_id() {
+ self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+/// Converts a specific `GenericBound` from the AST into a set of
+/// predicates that apply to the self type. A vector is returned
+/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
+/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
+/// and `<T as Bar>::X == i32`).
+fn predicates_from_bound<'tcx>(
+ astconv: &dyn AstConv<'tcx>,
+ param_ty: Ty<'tcx>,
+ bound: &'tcx hir::GenericBound<'tcx>,
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+) -> Vec<(ty::Predicate<'tcx>, Span)> {
+ let mut bounds = Bounds::default();
+ astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
+ bounds.predicates(astconv.tcx(), param_ty).collect()
+}
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index a1d1f125f..c29a645eb 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -284,7 +284,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
icx.to_ty(ty)
}
}
- ImplItemKind::TyAlias(ty) => {
+ ImplItemKind::Type(ty) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
check_feature_inherent_assoc_ty(tcx, item.span);
}
@@ -319,7 +319,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
- ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
+ ItemKind::Impl(hir::Impl { self_ty, .. }) => {
+ match self_ty.find_self_aliases() {
+ spans if spans.len() > 0 => {
+ tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
+ tcx.ty_error()
+ },
+ _ => icx.to_ty(*self_ty),
+ }
+ },
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
tcx.mk_fn_def(def_id.to_def_id(), substs)
@@ -340,10 +348,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
..
}) => {
if in_trait {
- span_bug!(item.span, "impl-trait in trait has no default")
- } else {
- find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+ assert!(tcx.impl_defaultness(owner).has_value());
}
+ find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
@@ -493,8 +500,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
},
def_id.to_def_id(),
);
- if let Some(assoc_item) = assoc_item {
- tcx.type_of(tcx.generics_of(assoc_item.def_id).params[idx].def_id)
+ if let Some(param)
+ = assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
+ {
+ tcx.type_of(param.def_id)
} else {
// FIXME(associated_const_equality): add a useful error message here.
tcx.ty_error_with_message(
@@ -564,6 +573,11 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
/// checked against it (we also carry the span of that first
/// type).
found: Option<ty::OpaqueHiddenType<'tcx>>,
+
+ /// In the presence of dead code, typeck may figure out a hidden type
+ /// while borrowck will now. We collect these cases here and check at
+ /// the end that we actually found a type that matches (modulo regions).
+ typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
}
impl ConstraintLocator<'_> {
@@ -590,18 +604,23 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
return;
}
- if !tables.concrete_opaque_types.contains_key(&self.def_id) {
+ let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
debug!("no constraints in typeck results");
return;
+ };
+ if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
+ self.typeck_types.push(typeck_hidden_ty);
}
+
// Use borrowck to get the type with unerased regions.
let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
debug!(?concrete_opaque_types);
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
debug!(?concrete_type, "found constraint");
- if let Some(prev) = self.found {
- if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
+ if let Some(prev) = &mut self.found {
+ if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
prev.report_mismatch(&concrete_type, self.tcx);
+ prev.ty = self.tcx.ty_error();
}
} else {
self.found = Some(concrete_type);
@@ -624,31 +643,31 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.def_id);
- self.check(it.def_id);
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let scope = tcx.hir().get_defining_scope(hir_id);
- let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None };
+ let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None, typeck_types: vec![] };
debug!(?scope);
@@ -678,16 +697,32 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
}
}
- match locator.found {
- Some(hidden) => hidden.ty,
- None => {
- tcx.sess.emit_err(UnconstrainedOpaqueType {
- span: tcx.def_span(def_id),
- name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
- });
- tcx.ty_error()
+ let Some(hidden) = locator.found else {
+ tcx.sess.emit_err(UnconstrainedOpaqueType {
+ span: tcx.def_span(def_id),
+ name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+ what: match tcx.hir().get(scope) {
+ _ if scope == hir::CRATE_HIR_ID => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
+ _ => "item",
+ },
+ });
+ return tcx.ty_error();
+ };
+
+ // Only check against typeck if we didn't already error
+ if !hidden.ty.references_error() {
+ for concrete_type in locator.typeck_types {
+ if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
+ && !(concrete_type, hidden).references_error()
+ {
+ hidden.report_mismatch(&concrete_type, tcx);
+ }
}
}
+
+ hidden.ty
}
fn find_opaque_ty_constraints_for_rpit(
@@ -743,24 +778,24 @@ fn find_opaque_ty_constraints_for_rpit(
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id != self.def_id {
- self.check(it.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.def_id);
- self.check(it.def_id);
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}
@@ -788,20 +823,15 @@ fn find_opaque_ty_constraints_for_rpit(
// the `concrete_opaque_types` table.
tcx.ty_error()
} else {
- table
- .concrete_opaque_types
- .get(&def_id)
- .copied()
- .unwrap_or_else(|| {
- // We failed to resolve the opaque type or it
- // resolves to itself. We interpret this as the
- // no values of the hidden type ever being constructed,
- // so we can just make the hidden type be `!`.
- // For backwards compatibility reasons, we fall back to
- // `()` until we the diverging default is changed.
- Some(tcx.mk_diverging_default())
- })
- .expect("RPIT always have a hidden type from typeck")
+ table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
+ // We failed to resolve the opaque type or it
+ // resolves to itself. We interpret this as the
+ // no values of the hidden type ever being constructed,
+ // so we can just make the hidden type be `!`.
+ // For backwards compatibility reasons, we fall back to
+ // `()` until we the diverging default is changed.
+ tcx.mk_diverging_default()
+ })
}
})
}
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 8428e4664..213b89fc7 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -114,9 +114,9 @@ pub fn identify_constrained_generic_params<'tcx>(
/// ```
/// The impl's predicates are collected from left to right. Ignoring
/// the implicit `Sized` bounds, these are
-/// * T: Debug
-/// * U: Iterator
-/// * <U as Iterator>::Item = T -- a desugared ProjectionPredicate
+/// * `T: Debug`
+/// * `U: Iterator`
+/// * `<U as Iterator>::Item = T` -- a desugared ProjectionPredicate
///
/// When we, for example, try to go over the trait-reference
/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
@@ -132,12 +132,16 @@ pub fn identify_constrained_generic_params<'tcx>(
///
/// We *do* have to be somewhat careful when projection targets contain
/// projections themselves, for example in
+///
+/// ```ignore (illustrative)
/// impl<S,U,V,W> Trait for U where
/// /* 0 */ S: Iterator<Item = U>,
/// /* - */ U: Iterator,
/// /* 1 */ <U as Iterator>::Item: ToOwned<Owned=(W,<V as Iterator>::Item)>
/// /* 2 */ W: Iterator<Item = V>
/// /* 3 */ V: Debug
+/// ```
+///
/// we have to evaluate the projections in the order I wrote them:
/// `V: Debug` requires `V` to be evaluated. The only projection that
/// *determines* `V` is 2 (1 contains it, but *does not determine it*,
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 0d2e66745..d5b1a7ce1 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1,23 +1,13 @@
-//! Errors emitted by typeck.
+//! Errors emitted by `rustc_hir_analysis`.
+
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
+use rustc_errors::{IntoDiagnostic, MultiSpan};
+use rustc_macros::{Diagnostic, LintDiagnostic};
use rustc_middle::ty::Ty;
-use rustc_session::SessionDiagnostic;
use rustc_span::{symbol::Ident, Span, Symbol};
-#[derive(SessionDiagnostic)]
-#[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")]
-pub struct FieldMultiplySpecifiedInInitializer {
- #[primary_span]
- #[label]
- pub span: Span,
- #[label(typeck::previous_use_label)]
- pub prev_span: Span,
- pub ident: Ident,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unrecognized_atomic_operation, code = "E0092")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unrecognized_atomic_operation, code = "E0092")]
pub struct UnrecognizedAtomicOperation<'a> {
#[primary_span]
#[label]
@@ -25,8 +15,8 @@ pub struct UnrecognizedAtomicOperation<'a> {
pub op: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_wrong_number_of_generic_arguments_to_intrinsic, code = "E0094")]
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[primary_span]
#[label]
@@ -36,8 +26,8 @@ pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
pub descr: &'a str,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unrecognized_intrinsic_function, code = "E0093")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unrecognized_intrinsic_function, code = "E0093")]
pub struct UnrecognizedIntrinsicFunction {
#[primary_span]
#[label]
@@ -45,93 +35,86 @@ pub struct UnrecognizedIntrinsicFunction {
pub name: Symbol,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_lifetimes_or_bounds_mismatch_on_trait, code = "E0195")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::generics_label)]
+ #[label(generics_label)]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::drop_impl_on_wrong_item, code = "E0120")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::field_already_declared, code = "E0124")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_already_declared, code = "E0124")]
pub struct FieldAlreadyDeclared {
pub field_name: Ident,
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::previous_decl_label)]
+ #[label(previous_decl_label)]
pub prev_span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::copy_impl_on_type_with_dtor, code = "E0184")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_copy_impl_on_type_with_dtor, code = "E0184")]
pub struct CopyImplOnTypeWithDtor {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::multiple_relaxed_default_bounds, code = "E0203")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
pub struct MultipleRelaxedDefaultBounds {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::copy_impl_on_non_adt, code = "E0206")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_copy_impl_on_non_adt, code = "E0206")]
pub struct CopyImplOnNonAdt {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::trait_object_declared_with_no_traits, code = "E0224")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
pub struct TraitObjectDeclaredWithNoTraits {
#[primary_span]
pub span: Span,
- #[label(typeck::alias_span)]
+ #[label(alias_span)]
pub trait_alias_span: Option<Span>,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::ambiguous_lifetime_bound, code = "E0227")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_ambiguous_lifetime_bound, code = "E0227")]
pub struct AmbiguousLifetimeBound {
#[primary_span]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::assoc_type_binding_not_allowed, code = "E0229")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_assoc_type_binding_not_allowed, code = "E0229")]
pub struct AssocTypeBindingNotAllowed {
#[primary_span]
#[label]
pub span: Span,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::functional_record_update_on_non_struct, code = "E0436")]
-pub struct FunctionalRecordUpdateOnNonStruct {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::typeof_reserved_keyword_used, code = "E0516")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_typeof_reserved_keyword_used, code = "E0516")]
pub struct TypeofReservedKeywordUsed<'tcx> {
pub ty: Ty<'tcx>,
#[primary_span]
@@ -141,104 +124,26 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
pub opt_sugg: Option<(Span, Applicability)>,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::return_stmt_outside_of_fn_body, code = "E0572")]
-pub struct ReturnStmtOutsideOfFnBody {
- #[primary_span]
- pub span: Span,
- #[label(typeck::encl_body_label)]
- pub encl_body_span: Option<Span>,
- #[label(typeck::encl_fn_label)]
- pub encl_fn_span: Option<Span>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::yield_expr_outside_of_generator, code = "E0627")]
-pub struct YieldExprOutsideOfGenerator {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::struct_expr_non_exhaustive, code = "E0639")]
-pub struct StructExprNonExhaustive {
- #[primary_span]
- pub span: Span,
- pub what: &'static str,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::value_of_associated_struct_already_specified, code = "E0719")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_value_of_associated_struct_already_specified, code = "E0719")]
pub struct ValueOfAssociatedStructAlreadySpecified {
#[primary_span]
#[label]
pub span: Span,
- #[label(typeck::previous_bound_label)]
+ #[label(previous_bound_label)]
pub prev_span: Span,
pub item_name: Ident,
pub def_path: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::address_of_temporary_taken, code = "E0745")]
-pub struct AddressOfTemporaryTaken {
- #[primary_span]
- #[label]
- pub span: Span,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum AddReturnTypeSuggestion {
- #[suggestion(
- typeck::add_return_type_add,
- code = "-> {found} ",
- applicability = "machine-applicable"
- )]
- Add {
- #[primary_span]
- span: Span,
- found: String,
- },
- #[suggestion(
- typeck::add_return_type_missing_here,
- code = "-> _ ",
- applicability = "has-placeholders"
- )]
- MissingHere {
- #[primary_span]
- span: Span,
- },
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum ExpectedReturnTypeLabel<'tcx> {
- #[label(typeck::expected_default_return_type)]
- Unit {
- #[primary_span]
- span: Span,
- },
- #[label(typeck::expected_return_type)]
- Other {
- #[primary_span]
- span: Span,
- expected: Ty<'tcx>,
- },
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(typeck::unconstrained_opaque_type)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unconstrained_opaque_type)]
#[note]
pub struct UnconstrainedOpaqueType {
#[primary_span]
pub span: Span,
pub name: Symbol,
+ pub what: &'static str,
}
pub struct MissingTypeParams {
@@ -249,12 +154,12 @@ pub struct MissingTypeParams {
pub empty_generic_args: bool,
}
-// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`.
-impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
+// Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
+impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = handler.struct_span_err_with_code(
self.span,
- rustc_errors::fluent::typeck::missing_type_params,
+ rustc_errors::fluent::hir_analysis_missing_type_params,
error_code!(E0393),
);
err.set_arg("parameterCount", self.missing_type_params.len());
@@ -267,7 +172,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
.join(", "),
);
- err.span_label(self.def_span, rustc_errors::fluent::typeck::label);
+ err.span_label(self.def_span, rustc_errors::fluent::label);
let mut suggested = false;
// Don't suggest setting the type params if there are some already: the order is
@@ -282,7 +187,7 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
// least we can clue them to the correct syntax `Iterator<Type>`.
err.span_suggestion(
self.span,
- rustc_errors::fluent::typeck::suggestion,
+ rustc_errors::fluent::suggestion,
format!(
"{}<{}>",
snippet,
@@ -298,16 +203,16 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
}
}
if !suggested {
- err.span_label(self.span, rustc_errors::fluent::typeck::no_suggestion_label);
+ err.span_label(self.span, rustc_errors::fluent::no_suggestion_label);
}
- err.note(rustc_errors::fluent::typeck::note);
+ err.note(rustc_errors::fluent::note);
err
}
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::manual_implementation, code = "E0183")]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_manual_implementation, code = "E0183")]
#[help]
pub struct ManualImplementation {
#[primary_span]
@@ -316,22 +221,22 @@ pub struct ManualImplementation {
pub trait_name: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::substs_on_overridden_impl)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_substs_on_overridden_impl)]
pub struct SubstsOnOverriddenImpl {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(typeck::unused_extern_crate)]
+#[diag(hir_analysis_unused_extern_crate)]
pub struct UnusedExternCrate {
#[suggestion(applicability = "machine-applicable", code = "")]
pub span: Span,
}
#[derive(LintDiagnostic)]
-#[diag(typeck::extern_crate_not_idiomatic)]
+#[diag(hir_analysis_extern_crate_not_idiomatic)]
pub struct ExternCrateNotIdiomatic {
#[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
pub span: Span,
@@ -339,9 +244,39 @@ pub struct ExternCrateNotIdiomatic {
pub suggestion_code: String,
}
-#[derive(SessionDiagnostic)]
-#[diag(typeck::expected_used_symbol)]
+#[derive(Diagnostic)]
+#[diag(hir_analysis_expected_used_symbol)]
pub struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_impl_for_non_const_trait)]
+pub struct ConstImplForNonConstTrait {
+ #[primary_span]
+ pub trait_ref_span: Span,
+ pub trait_name: String,
+ #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
+ pub local_trait_span: Option<Span>,
+ #[note]
+ pub marking: (),
+ #[note(adding)]
+ pub adding: (),
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_bound_for_non_const_trait)]
+pub struct ConstBoundForNonConstTrait {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_in_impl_self)]
+pub struct SelfInImplSelf {
+ #[primary_span]
+ pub span: MultiSpan,
+ #[note]
+ pub note: (),
+}
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 7b080dc29..b0fdfcf38 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -64,38 +64,36 @@ fn diagnostic_hir_wf_check<'tcx>(
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
- self.tcx.infer_ctxt().enter(|infcx| {
- let tcx_ty =
- self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
- let cause = traits::ObligationCause::new(
- ty.span,
- self.hir_id,
- traits::ObligationCauseCode::WellFormed(None),
- );
- let errors = traits::fully_solve_obligation(
- &infcx,
- traits::Obligation::new(
- cause,
- self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
- .to_predicate(self.tcx),
- ),
- );
- if !errors.is_empty() {
- debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
- for error in errors {
- if error.obligation.predicate == self.predicate {
- // Save the cause from the greatest depth - this corresponds
- // to picking more-specific types (e.g. `MyStruct<u8>`)
- // over less-specific types (e.g. `Option<MyStruct<u8>>`)
- if self.depth >= self.cause_depth {
- self.cause = Some(error.obligation.cause);
- self.cause_depth = self.depth
- }
+ let infcx = self.tcx.infer_ctxt().build();
+ let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
+ let cause = traits::ObligationCause::new(
+ ty.span,
+ self.hir_id,
+ traits::ObligationCauseCode::WellFormed(None),
+ );
+ let errors = traits::fully_solve_obligation(
+ &infcx,
+ traits::Obligation::new(
+ cause,
+ self.param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+ .to_predicate(self.tcx),
+ ),
+ );
+ if !errors.is_empty() {
+ debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
+ for error in errors {
+ if error.obligation.predicate == self.predicate {
+ // Save the cause from the greatest depth - this corresponds
+ // to picking more-specific types (e.g. `MyStruct<u8>`)
+ // over less-specific types (e.g. `Option<MyStruct<u8>>`)
+ if self.depth >= self.cause_depth {
+ self.cause = Some(error.obligation.cause);
+ self.cause_depth = self.depth
}
}
}
- });
+ }
self.depth += 1;
intravisit::walk_ty(self, ty);
self.depth -= 1;
@@ -119,7 +117,7 @@ fn diagnostic_hir_wf_check<'tcx>(
let ty = match loc {
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
hir::Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::TyAlias(ty) => Some(ty),
+ hir::ImplItemKind::Type(ty) => Some(ty),
hir::ImplItemKind::Const(ty, _) => Some(ty),
ref item => bug!("Unexpected ImplItem {:?}", item),
},
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 9fee1eaae..136f61999 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -11,7 +11,7 @@
use crate::constrained_generic_params as cgp;
use min_specialization::check_min_specialization;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
@@ -19,8 +19,6 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::{Span, Symbol};
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-
mod min_specialization;
/// Checks that all the type/lifetime parameters on an impl also
@@ -57,11 +55,10 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let min_specialization = tcx.features().min_specialization;
let module = tcx.hir_module_items(module_def_id);
for id in module.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
- enforce_impl_params_are_constrained(tcx, id.def_id);
- enforce_impl_items_are_distinct(tcx, id.def_id);
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+ enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
if min_specialization {
- check_min_specialization(tcx, id.def_id);
+ check_min_specialization(tcx, id.owner_id.def_id);
}
}
}
@@ -194,35 +191,3 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
}
err.emit();
}
-
-/// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
- let mut seen_type_items = FxHashMap::default();
- let mut seen_value_items = FxHashMap::default();
- for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {
- let impl_item = tcx.associated_item(impl_item_ref);
- let seen_items = match impl_item.kind {
- ty::AssocKind::Type => &mut seen_type_items,
- _ => &mut seen_value_items,
- };
- let span = tcx.def_span(impl_item_ref);
- let ident = impl_item.ident(tcx);
- match seen_items.entry(ident.normalize_to_macros_2_0()) {
- Occupied(entry) => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0201,
- "duplicate definitions with name `{}`:",
- ident
- );
- err.span_label(*entry.get(), format!("previous definition of `{}` here", ident));
- err.span_label(span, "duplicate definition");
- err.emit();
- }
- Vacant(entry) => {
- entry.insert(span);
- }
- }
- }
-}
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 2741d9f77..e806e9487 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -77,7 +77,7 @@ use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
@@ -130,8 +130,10 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
///
/// Example
///
+/// ```ignore (illustrative)
/// impl<A, B> Foo<A> for B { /* impl2 */ }
/// impl<C> Foo<Vec<C>> for C { /* impl1 */ }
+/// ```
///
/// Would return `S1 = [C]` and `S2 = [Vec<C>, C]`.
fn get_impl_substs<'tcx>(
@@ -139,34 +141,33 @@ fn get_impl_substs<'tcx>(
impl1_def_id: LocalDefId,
impl2_node: Node,
) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
- tcx.infer_ctxt().enter(|ref infcx| {
- let ocx = ObligationCtxt::new(infcx);
- let param_env = tcx.param_env(impl1_def_id);
- let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+ let param_env = tcx.param_env(impl1_def_id);
+ let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
- let assumed_wf_types =
- ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
+ let assumed_wf_types =
+ ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
- let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
- let impl2_substs =
- translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
+ let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
+ let impl2_substs =
+ translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- ocx.infcx.report_fulfillment_errors(&errors, None, false);
- return None;
- }
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ return None;
+ }
- let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
- let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
- infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
- let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
- let span = tcx.def_span(impl1_def_id);
- tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
- return None;
- };
- Some((impl1_substs, impl2_substs))
- })
+ let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
+ let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
+ infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
+ let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
+ let span = tcx.def_span(impl1_def_id);
+ tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+ return None;
+ };
+ Some((impl1_substs, impl2_substs))
}
/// Returns a list of all of the unconstrained subst of the given impl.
@@ -226,13 +227,17 @@ fn unconstrained_parent_impl_substs<'tcx>(
///
/// For example forbid the following:
///
+/// ```ignore (illustrative)
/// impl<A> Tr for A { }
/// impl<B> Tr for (B, B) { }
+/// ```
///
/// Note that only consider the unconstrained parameters of the base impl:
///
+/// ```ignore (illustrative)
/// impl<S, I: IntoIterator<Item = S>> Tr<S> for I { }
/// impl<T> Tr<T> for Vec<T> { }
+/// ```
///
/// The substs for the parent impl here are `[T, Vec<T>]`, which repeats `T`,
/// but `S` is constrained in the parent impl, so `parent_substs` is only
@@ -257,8 +262,10 @@ fn check_duplicate_params<'tcx>(
///
/// For example forbid the following:
///
+/// ```ignore (illustrative)
/// impl<A> Tr for A { }
/// impl Tr for &'static i32 { }
+/// ```
fn check_static_lifetimes<'tcx>(
tcx: TyCtxt<'tcx>,
parent_substs: &Vec<GenericArg<'tcx>>,
@@ -344,23 +351,21 @@ fn check_predicates<'tcx>(
// Include the well-formed predicates of the type parameters of the impl.
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
- tcx.infer_ctxt().enter(|ref infcx| {
- let obligations = wf::obligations(
- infcx,
- tcx.param_env(impl1_def_id),
- tcx.hir().local_def_id_to_hir_id(impl1_def_id),
- 0,
- arg,
- span,
- )
- .unwrap();
+ let infcx = &tcx.infer_ctxt().build();
+ let obligations = wf::obligations(
+ infcx,
+ tcx.param_env(impl1_def_id),
+ tcx.hir().local_def_id_to_hir_id(impl1_def_id),
+ 0,
+ arg,
+ span,
+ )
+ .unwrap();
- assert!(!obligations.needs_infer());
- impl2_predicates.extend(
- traits::elaborate_obligations(tcx, obligations)
- .map(|obligation| obligation.predicate),
- )
- })
+ assert!(!obligations.needs_infer());
+ impl2_predicates.extend(
+ traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
+ )
}
impl2_predicates.extend(
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
@@ -423,13 +428,10 @@ fn trait_predicate_kind<'tcx>(
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::NotConst,
- polarity: _,
- }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
- ty::PredicateKind::Trait(_)
- | ty::PredicateKind::RegionOutlives(_)
+ ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
+ Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
+ }
+ ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::WellFormed(_)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index b1ce972e1..525cd2419 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -64,15 +64,13 @@ This API is completely unstable and subject to change.
#![feature(if_let_guard)]
#![feature(is_sorted)]
#![feature(iter_intersperse)]
-#![cfg_attr(bootstrap, feature(label_break_value))]
#![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(let_else))]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(once_cell)]
#![feature(slice_partition_dedup)]
#![feature(try_blocks)]
-#![feature(is_some_with)]
+#![feature(is_some_and)]
#![feature(type_alias_impl_trait)]
#![recursion_limit = "256"]
@@ -84,20 +82,19 @@ extern crate rustc_middle;
// These are used by Clippy.
pub mod check;
-pub mod expr_use_visitor;
-mod astconv;
+pub mod astconv;
mod bounds;
mod check_unused;
mod coherence;
-mod collect;
+// FIXME: This module shouldn't be public.
+pub mod collect;
mod constrained_generic_params;
mod errors;
pub mod hir_wf_check;
mod impl_wf_check;
-mod mem_categorization;
mod outlives;
-mod structured_errors;
+pub mod structured_errors;
mod variance;
use rustc_errors::{struct_span_err, ErrorGuaranteed};
@@ -112,7 +109,7 @@ use rustc_middle::util;
use rustc_session::config::EntryFnType;
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::iter;
@@ -143,24 +140,23 @@ fn require_same_types<'tcx>(
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> bool {
- tcx.infer_ctxt().enter(|ref infcx| {
- let param_env = ty::ParamEnv::empty();
- let errors = match infcx.at(cause, param_env).eq(expected, actual) {
- Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
- Err(err) => {
- infcx.report_mismatched_types(cause, expected, actual, err).emit();
- return false;
- }
- };
+ let infcx = &tcx.infer_ctxt().build();
+ let param_env = ty::ParamEnv::empty();
+ let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+ Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
+ Err(err) => {
+ infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
+ return false;
+ }
+ };
- match &errors[..] {
- [] => true,
- errors => {
- infcx.report_fulfillment_errors(errors, None, false);
- false
- }
+ match &errors[..] {
+ [] => true,
+ errors => {
+ infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+ false
}
- })
+ }
}
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
@@ -307,23 +303,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true;
}
let return_ty = return_ty.skip_binder();
- tcx.infer_ctxt().enter(|infcx| {
- // Main should have no WC, so empty param env is OK here.
- let param_env = ty::ParamEnv::empty();
- let cause = traits::ObligationCause::new(
- return_ty_span,
- main_diagnostics_hir_id,
- ObligationCauseCode::MainFunctionType,
- );
- let ocx = traits::ObligationCtxt::new(&infcx);
- let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
- ocx.register_bound(cause, param_env, norm_return_ty, term_did);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- error = true;
- }
- });
+ let infcx = tcx.infer_ctxt().build();
+ // Main should have no WC, so empty param env is OK here.
+ let param_env = ty::ParamEnv::empty();
+ let cause = traits::ObligationCause::new(
+ return_ty_span,
+ main_diagnostics_hir_id,
+ ObligationCauseCode::MainFunctionType,
+ );
+ let ocx = traits::ObligationCtxt::new(&infcx);
+ let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+ ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ error = true;
+ }
// now we can take the return type of the given main function
expected_return_type = main_fnsig.output();
} else {
@@ -386,7 +381,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
error = true;
}
if let hir::IsAsync::Async = sig.header.asyncness {
- let span = tcx.def_span(it.def_id);
+ let span = tcx.def_span(it.owner_id);
struct_span_err!(
tcx.sess,
span,
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 7534482cc..7534482cc 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index 3b779280e..90c6edb65 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -1,8 +1,8 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::Span;
use super::explicit::ExplicitPredicatesMap;
@@ -29,7 +29,7 @@ pub(super) fn infer_predicates<'tcx>(
// Visit all the crates and infer predicates
for id in tcx.hir().items() {
- let item_did = id.def_id;
+ let item_did = id.owner_id;
debug!("InferVisitor::visit_item(item={:?})", item_did);
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index e50c26765..e50c26765 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index eb0e12034..fa2ac5659 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -6,11 +6,11 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
for id in tcx.hir().items() {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_outlives) {
- let inferred_outlives_of = tcx.inferred_outlives_of(id.def_id);
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) {
+ let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
struct_span_err!(
tcx.sess,
- tcx.def_span(id.def_id),
+ tcx.def_span(id.owner_id),
E0640,
"{:?}",
inferred_outlives_of
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 3e8d023fb..0409c7081 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -96,6 +96,23 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
.or_insert(span);
}
+ Component::Opaque(def_id, substs) => {
+ // This would arise from something like:
+ //
+ // ```rust
+ // type Opaque<T> = impl Sized;
+ // fn defining<T>() -> Opaque<T> {}
+ // struct Ss<'a, T>(&'a Opaque<T>);
+ // ```
+ //
+ // Here we want to have an implied bound `Opaque<T>: 'a`
+
+ let ty = tcx.mk_opaque(def_id, substs);
+ required_predicates
+ .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
+ .or_insert(span);
+ }
+
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF
diff --git a/compiler/rustc_typeck/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs
index 0b46fce17..0b46fce17 100644
--- a/compiler/rustc_typeck/src/structured_errors.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 324df313e..324df313e 100644
--- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index bb6088054..bb6088054 100644
--- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 435912464..435912464 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eaf0310d5..eaf0310d5 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
diff --git a/compiler/rustc_typeck/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 82103c5a0..82103c5a0 100644
--- a/compiler/rustc_typeck/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
diff --git a/compiler/rustc_typeck/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index 97aca621a..97aca621a 100644
--- a/compiler/rustc_typeck/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1f763011e..1f763011e 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 2ba87db88..83ed3e44b 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -6,9 +6,10 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
for id in tcx.hir().items() {
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_variance) {
- let variances_of = tcx.variances_of(id.def_id);
- struct_span_err!(tcx.sess, tcx.def_span(id.def_id), E0208, "{:?}", variances_of).emit();
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
+ let variances_of = tcx.variances_of(id.owner_id);
+ struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
+ .emit();
}
}
}
diff --git a/compiler/rustc_typeck/src/variance/xform.rs b/compiler/rustc_hir_analysis/src/variance/xform.rs
index 027f0859f..027f0859f 100644
--- a/compiler/rustc_typeck/src/variance/xform.rs
+++ b/compiler/rustc_hir_analysis/src/variance/xform.rs
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index 46a8e7dee..1ea7be1ae 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.0.0"
edition = "2021"
[lib]
-doctest = false
[dependencies]
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 35a58296e..da27554a2 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -887,7 +887,7 @@ impl<'a> State<'a> {
self.end(); // need to close a box
self.ann.nested(self, Nested::Body(body));
}
- hir::ImplItemKind::TyAlias(ty) => {
+ hir::ImplItemKind::Type(ty) => {
self.print_associated_type(ii.ident, ii.generics, None, Some(ty));
}
}
@@ -1687,7 +1687,11 @@ impl<'a> State<'a> {
let mut nonelided_generic_args: bool = false;
let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
- GenericArg::Lifetime(lt) => lt.is_elided(),
+ GenericArg::Lifetime(lt) if lt.is_elided() => true,
+ GenericArg::Lifetime(_) => {
+ nonelided_generic_args = true;
+ false
+ }
_ => {
nonelided_generic_args = true;
true
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
new file mode 100644
index 000000000..093f9bb84
--- /dev/null
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_hir_typeck"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_hir_pretty = { path = "../rustc_hir_pretty" }
+rustc_lint = { path = "../rustc_lint" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 20332e75c..2b15d4dcd 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -1,10 +1,10 @@
-use crate::check::coercion::{AsCoercionSite, CoerceMany};
-use crate::check::{Diverges, Expectation, FnCtxt, Needs};
+use crate::coercion::{AsCoercionSite, CoerceMany};
+use crate::{Diverges, Expectation, FnCtxt, Needs};
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, Subst, ToPredicate, Ty};
+use rustc_middle::ty::{self, ToPredicate, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
@@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(ret) = self
.tcx
.hir()
- .find_by_def_id(self.body_id.owner)
+ .find_by_def_id(self.body_id.owner.def_id)
.and_then(|owner| owner.fn_decl())
.map(|decl| decl.output.span())
else { return; };
@@ -259,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help("consider adding an `else` block that evaluates to the expected type");
error = true;
},
- ret_reason.is_none(),
+ false,
);
error
}
@@ -495,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.typeck_results
.borrow()
.liberated_fn_sigs()
- .get(hir::HirId::make_owner(self.body_id.owner))?;
+ .get(hir::HirId::make_owner(self.body_id.owner.def_id))?;
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
@@ -514,8 +514,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
for ty in [first_ty, second_ty] {
- for pred in self.tcx.bound_explicit_item_bounds(rpit_def_id).transpose_iter() {
- let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx, substs);
+ for (pred, _) in self
+ .tcx
+ .bound_explicit_item_bounds(rpit_def_id)
+ .subst_iter_copied(self.tcx, substs)
+ {
let pred = match pred.kind().skip_binder() {
ty::PredicateKind::Trait(mut trait_pred) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
diff --git a/compiler/rustc_typeck/src/check/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 59c366ad7..59c366ad7 100644
--- a/compiler/rustc_typeck/src/check/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 0d35c2479..1b33f2f02 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,8 +1,10 @@
+use super::method::probe::{IsSuggestion, Mode, ProbeScope};
use super::method::MethodCallee;
-use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
-use crate::type_error_struct;
+use super::{Expectation, FnCtxt, TupleArgumentsFlag};
-use rustc_errors::{struct_span_err, Applicability, Diagnostic};
+use crate::type_error_struct;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::{struct_span_err, Applicability, Diagnostic, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{self, Namespace, Res};
use rustc_hir::def_id::DefId;
@@ -17,7 +19,7 @@ use rustc_infer::{
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
};
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident};
@@ -25,6 +27,7 @@ use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::iter;
@@ -60,6 +63,7 @@ pub fn check_legal_trait_for_method_call(
}
}
+#[derive(Debug)]
enum CallStep<'tcx> {
Builtin(Ty<'tcx>),
DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
@@ -188,6 +192,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
+ ty::Error(_) => {
+ return None;
+ }
+
_ => {}
}
@@ -394,140 +402,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::FnPtr(sig) => (sig, None),
_ => {
- let mut unit_variant = None;
- if let hir::ExprKind::Path(qpath) = &callee_expr.kind
- && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
- = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
- // Only suggest removing parens if there are no arguments
- && arg_exprs.is_empty()
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
+ && let [segment] = path.segments
+ && let Some(mut diag) = self
+ .tcx
+ .sess
+ .diagnostic()
+ .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
{
- let descr = match kind {
- def::CtorOf::Struct => "struct",
- def::CtorOf::Variant => "enum variant",
- };
- let removal_span =
- callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
- unit_variant =
- Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
- }
-
- let callee_ty = self.resolve_vars_if_possible(callee_ty);
- let mut err = type_error_struct!(
- self.tcx.sess,
- callee_expr.span,
- callee_ty,
- E0618,
- "expected function, found {}",
- match &unit_variant {
- Some((_, kind, path)) => format!("{kind} `{path}`"),
- None => format!("`{callee_ty}`"),
- }
- );
-
- self.identify_bad_closure_def_and_call(
- &mut err,
- call_expr.hir_id,
- &callee_expr.kind,
- callee_expr.span,
- );
-
- if let Some((removal_span, kind, path)) = &unit_variant {
- err.span_suggestion_verbose(
- *removal_span,
- &format!(
- "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
- ),
- "",
- Applicability::MachineApplicable,
- );
- }
-
- let mut inner_callee_path = None;
- let def = match callee_expr.kind {
- hir::ExprKind::Path(ref qpath) => {
- self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
- }
- hir::ExprKind::Call(ref inner_callee, _) => {
- // If the call spans more than one line and the callee kind is
- // itself another `ExprCall`, that's a clue that we might just be
- // missing a semicolon (Issue #51055)
- let call_is_multiline =
- self.tcx.sess.source_map().is_multiline(call_expr.span);
- if call_is_multiline {
- err.span_suggestion(
- callee_expr.span.shrink_to_hi(),
- "consider using a semicolon here",
- ";",
- Applicability::MaybeIncorrect,
- );
- }
- if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
- inner_callee_path = Some(inner_qpath);
- self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
- } else {
- Res::Err
- }
- }
- _ => Res::Err,
- };
-
- if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
- if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
- && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ // Try suggesting `foo(a)` -> `a.foo()` if possible.
+ if let Some(ty) =
+ self.suggest_call_as_method(
+ &mut diag,
+ segment,
+ arg_exprs,
+ call_expr,
+ expected
+ )
{
- let descr = match maybe_def {
- DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
- DefIdOrName::Name(name) => name,
- };
- err.span_label(
- callee_expr.span,
- format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
- );
- if let DefIdOrName::DefId(def_id) = maybe_def
- && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
- {
- err.span_label(def_span, "the callable type is defined here");
- }
+ diag.emit();
+ return ty;
} else {
- err.span_label(call_expr.span, "call expression requires function");
+ diag.emit();
}
}
- if let Some(span) = self.tcx.hir().res_span(def) {
- let callee_ty = callee_ty.to_string();
- let label = match (unit_variant, inner_callee_path) {
- (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
- (_, Some(hir::QPath::Resolved(_, path))) => self
- .tcx
- .sess
- .source_map()
- .span_to_snippet(path.span)
- .ok()
- .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
- _ => {
- match def {
- // Emit a different diagnostic for local variables, as they are not
- // type definitions themselves, but rather variables *of* that type.
- Res::Local(hir_id) => Some(format!(
- "`{}` has type `{}`",
- self.tcx.hir().name(hir_id),
- callee_ty
- )),
- Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
- Some(format!(
- "`{}` defined here",
- self.tcx.def_path_str(def_id),
- ))
- }
- _ => Some(format!("`{callee_ty}` defined here")),
- }
- }
- };
- if let Some(label) = label {
- err.span_label(span, label);
- }
- }
- err.emit();
+ self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
// This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to
@@ -574,6 +474,243 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_sig.output()
}
+ /// Attempts to reinterpret `method(rcvr, args...)` as `rcvr.method(args...)`
+ /// and suggesting the fix if the method probe is successful.
+ fn suggest_call_as_method(
+ &self,
+ diag: &mut Diagnostic,
+ segment: &'tcx hir::PathSegment<'tcx>,
+ arg_exprs: &'tcx [hir::Expr<'tcx>],
+ call_expr: &'tcx hir::Expr<'tcx>,
+ expected: Expectation<'tcx>,
+ ) -> Option<Ty<'tcx>> {
+ if let [callee_expr, rest @ ..] = arg_exprs {
+ let callee_ty = self.check_expr(callee_expr);
+ // First, do a probe with `IsSuggestion(true)` to avoid emitting
+ // any strange errors. If it's successful, then we'll do a true
+ // method lookup.
+ let Ok(pick) = self
+ .probe_for_name(
+ call_expr.span,
+ Mode::MethodCall,
+ segment.ident,
+ IsSuggestion(true),
+ callee_ty,
+ call_expr.hir_id,
+ // We didn't record the in scope traits during late resolution
+ // so we need to probe AllTraits unfortunately
+ ProbeScope::AllTraits,
+ ) else {
+ return None;
+ };
+
+ let pick = self.confirm_method(
+ call_expr.span,
+ callee_expr,
+ call_expr,
+ callee_ty,
+ pick,
+ segment,
+ );
+ if pick.illegal_sized_bound.is_some() {
+ return None;
+ }
+
+ let up_to_rcvr_span = segment.ident.span.until(callee_expr.span);
+ let rest_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+ let rest_snippet = if let Some(first) = rest.first() {
+ self.tcx
+ .sess
+ .source_map()
+ .span_to_snippet(first.span.to(call_expr.span.shrink_to_hi()))
+ } else {
+ Ok(")".to_string())
+ };
+
+ if let Ok(rest_snippet) = rest_snippet {
+ let sugg = if callee_expr.precedence().order() >= PREC_POSTFIX {
+ vec![
+ (up_to_rcvr_span, "".to_string()),
+ (rest_span, format!(".{}({rest_snippet}", segment.ident)),
+ ]
+ } else {
+ vec![
+ (up_to_rcvr_span, "(".to_string()),
+ (rest_span, format!(").{}({rest_snippet}", segment.ident)),
+ ]
+ };
+ let self_ty = self.resolve_vars_if_possible(pick.callee.sig.inputs()[0]);
+ diag.multipart_suggestion(
+ format!(
+ "use the `.` operator to call the method `{}{}` on `{self_ty}`",
+ self.tcx
+ .associated_item(pick.callee.def_id)
+ .trait_container(self.tcx)
+ .map_or_else(
+ || String::new(),
+ |trait_def_id| self.tcx.def_path_str(trait_def_id) + "::"
+ ),
+ segment.ident
+ ),
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+
+ // Let's check the method fully now
+ let return_ty = self.check_method_argument_types(
+ segment.ident.span,
+ call_expr,
+ Ok(pick.callee),
+ rest,
+ TupleArgumentsFlag::DontTupleArguments,
+ expected,
+ );
+
+ return Some(return_ty);
+ }
+ }
+
+ None
+ }
+
+ fn report_invalid_callee(
+ &self,
+ call_expr: &'tcx hir::Expr<'tcx>,
+ callee_expr: &'tcx hir::Expr<'tcx>,
+ callee_ty: Ty<'tcx>,
+ arg_exprs: &'tcx [hir::Expr<'tcx>],
+ ) {
+ let mut unit_variant = None;
+ if let hir::ExprKind::Path(qpath) = &callee_expr.kind
+ && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _)
+ = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+ // Only suggest removing parens if there are no arguments
+ && arg_exprs.is_empty()
+ {
+ let descr = match kind {
+ def::CtorOf::Struct => "struct",
+ def::CtorOf::Variant => "enum variant",
+ };
+ let removal_span = callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi());
+ unit_variant = Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath)));
+ }
+
+ let callee_ty = self.resolve_vars_if_possible(callee_ty);
+ let mut err = type_error_struct!(
+ self.tcx.sess,
+ callee_expr.span,
+ callee_ty,
+ E0618,
+ "expected function, found {}",
+ match &unit_variant {
+ Some((_, kind, path)) => format!("{kind} `{path}`"),
+ None => format!("`{callee_ty}`"),
+ }
+ );
+
+ self.identify_bad_closure_def_and_call(
+ &mut err,
+ call_expr.hir_id,
+ &callee_expr.kind,
+ callee_expr.span,
+ );
+
+ if let Some((removal_span, kind, path)) = &unit_variant {
+ err.span_suggestion_verbose(
+ *removal_span,
+ &format!(
+ "`{path}` is a unit {kind}, and does not take parentheses to be constructed",
+ ),
+ "",
+ Applicability::MachineApplicable,
+ );
+ }
+
+ let mut inner_callee_path = None;
+ let def = match callee_expr.kind {
+ hir::ExprKind::Path(ref qpath) => {
+ self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
+ }
+ hir::ExprKind::Call(ref inner_callee, _) => {
+ // If the call spans more than one line and the callee kind is
+ // itself another `ExprCall`, that's a clue that we might just be
+ // missing a semicolon (Issue #51055)
+ let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
+ if call_is_multiline {
+ err.span_suggestion(
+ callee_expr.span.shrink_to_hi(),
+ "consider using a semicolon here",
+ ";",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
+ inner_callee_path = Some(inner_qpath);
+ self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
+ } else {
+ Res::Err
+ }
+ }
+ _ => Res::Err,
+ };
+
+ if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+ if let Some((maybe_def, output_ty, _)) =
+ self.extract_callable_info(callee_expr, callee_ty)
+ && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+ {
+ let descr = match maybe_def {
+ DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+ DefIdOrName::Name(name) => name,
+ };
+ err.span_label(
+ callee_expr.span,
+ format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+ );
+ if let DefIdOrName::DefId(def_id) = maybe_def
+ && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+ {
+ err.span_label(def_span, "the callable type is defined here");
+ }
+ } else {
+ err.span_label(call_expr.span, "call expression requires function");
+ }
+ }
+
+ if let Some(span) = self.tcx.hir().res_span(def) {
+ let callee_ty = callee_ty.to_string();
+ let label = match (unit_variant, inner_callee_path) {
+ (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")),
+ (_, Some(hir::QPath::Resolved(_, path))) => self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(path.span)
+ .ok()
+ .map(|p| format!("`{p}` defined here returns `{callee_ty}`")),
+ _ => {
+ match def {
+ // Emit a different diagnostic for local variables, as they are not
+ // type definitions themselves, but rather variables *of* that type.
+ Res::Local(hir_id) => Some(format!(
+ "`{}` has type `{}`",
+ self.tcx.hir().name(hir_id),
+ callee_ty
+ )),
+ Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => {
+ Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),))
+ }
+ _ => Some(format!("`{callee_ty}` defined here")),
+ }
+ }
+ };
+ if let Some(label) = label {
+ err.span_label(span, label);
+ }
+ }
+ err.emit();
+ }
+
fn confirm_deferred_closure_call(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 81a979865..d1dab0540 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -30,20 +30,18 @@
use super::FnCtxt;
-use crate::hir::def_id::DefId;
use crate::type_error_struct;
-use hir::def_id::LOCAL_CRATE;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
use rustc_session::lint;
use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
@@ -62,6 +60,8 @@ pub struct CastCheck<'tcx> {
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ /// whether the cast is made in a const context or not.
+ pub constness: hir::Constness,
}
/// The kind of pointer and associated metadata (thin, length or vtable) - we
@@ -204,85 +204,18 @@ fn make_invalid_casting_error<'a, 'tcx>(
)
}
-pub enum CastCheckResult<'tcx> {
- Ok,
- Deferred(CastCheck<'tcx>),
- Err(ErrorGuaranteed),
-}
-
-pub fn check_cast<'tcx>(
- fcx: &FnCtxt<'_, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- expr_ty: Ty<'tcx>,
- cast_ty: Ty<'tcx>,
- cast_span: Span,
- span: Span,
-) -> CastCheckResult<'tcx> {
- if cast_ty.is_dyn_star() {
- check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
- } else {
- match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
- Ok(check) => CastCheckResult::Deferred(check),
- Err(e) => CastCheckResult::Err(e),
- }
- }
-}
-
-fn check_dyn_star_cast<'tcx>(
- fcx: &FnCtxt<'_, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- expr_ty: Ty<'tcx>,
- cast_ty: Ty<'tcx>,
-) -> CastCheckResult<'tcx> {
- // Find the bounds in the dyn*. For eaxmple, if we have
- //
- // let x = 22_usize as dyn* (Clone + Debug + 'static)
- //
- // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
- let (existential_predicates, region) = match cast_ty.kind() {
- ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region),
- _ => panic!("Invalid dyn* cast_ty"),
- };
-
- let cause = ObligationCause::new(
- expr.span,
- fcx.body_id,
- // FIXME(dyn-star): Use a better obligation cause code
- ObligationCauseCode::MiscObligation,
- );
-
- // For each existential predicate (e.g., `?Self: Clone`) substitute
- // the type of the expression (e.g., `usize` in our example above)
- // and then require that the resulting predicate (e.g., `usize: Clone`)
- // holds (it does).
- for existential_predicate in existential_predicates.iter() {
- let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
- fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
- }
-
- // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
- fcx.register_predicate(Obligation::new(
- cause,
- fcx.param_env,
- fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
- ty::OutlivesPredicate(expr_ty, *region),
- ))),
- ));
-
- CastCheckResult::Ok
-}
-
impl<'a, 'tcx> CastCheck<'tcx> {
- fn new(
+ pub fn new(
fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr<'tcx>,
expr_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ constness: hir::Constness,
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
- let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
+ let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
// For better error messages, check for some obviously unsized
// cases now. We do a more thorough check at the end, once
@@ -596,7 +529,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
err.emit();
}
CastError::SizedUnsizedCast => {
- use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
+ use rustc_hir_analysis::structured_errors::{
+ SizedUnsizedCast, StructuredDiagnostic,
+ };
SizedUnsizedCast {
sess: &fcx.tcx.sess,
@@ -754,19 +689,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
} else {
("", lint::builtin::TRIVIAL_CASTS)
};
- fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
- err.build(&format!(
- "trivial {}cast: `{}` as `{}`",
- adjective,
- fcx.ty_to_string(t_expr),
- fcx.ty_to_string(t_cast)
- ))
- .help(&format!(
- "cast can be replaced by coercion; this might \
- require {type_asc_or}a temporary variable"
- ))
- .emit();
- });
+ fcx.tcx.struct_span_lint_hir(
+ lint,
+ self.expr.hir_id,
+ self.span,
+ DelayDm(|| {
+ format!(
+ "trivial {}cast: `{}` as `{}`",
+ adjective,
+ fcx.ty_to_string(t_expr),
+ fcx.ty_to_string(t_cast)
+ )
+ }),
+ |lint| {
+ lint.help(format!(
+ "cast can be replaced by coercion; this might \
+ require {type_asc_or}a temporary variable"
+ ))
+ },
+ );
}
#[instrument(skip(fcx), level = "debug")]
@@ -928,11 +869,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
- // FIXME(dyn-star): this needs more conditions...
- (_, DynStar) => Ok(CastKind::DynStarCast),
-
- // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts?
- (DynStar, _) => Err(CastError::IllegalCast),
+ (_, DynStar) | (DynStar, _) => {
+ if fcx.tcx.features().dyn_star {
+ bug!("should be handled by `try_coerce`")
+ } else {
+ Err(CastError::IllegalCast)
+ }
+ }
}
}
@@ -1074,12 +1017,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id,
self.span,
- |err| {
- err.build(&format!(
- "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
- self.expr_ty, self.cast_ty
- ))
- .emit();
+ DelayDm(|| format!(
+ "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+ self.expr_ty, self.cast_ty
+ )),
+ |lint| {
+ lint
},
);
}
@@ -1090,12 +1033,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
- |err| {
- let mut err = err.build(&format!(
+ DelayDm(|| format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
- ));
-
+ )),
+ |lint| {
let msg = "use `.addr()` to obtain the address of a pointer";
let expr_prec = self.expr.precedence().order();
@@ -1114,9 +1056,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(cast_span, format!(").addr(){scalar_cast}")),
];
- err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+ lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
} else {
- err.span_suggestion(
+ lint.span_suggestion(
cast_span,
msg,
format!(".addr(){scalar_cast}"),
@@ -1124,12 +1066,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
- err.help(
+ lint.help(
"if you can't comply with strict provenance and need to expose the pointer \
provenance you can use `.expose_addr()` instead"
);
- err.emit();
+ lint
},
);
}
@@ -1139,24 +1081,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
- |err| {
- let mut err = err.build(&format!(
- "strict provenance disallows casting integer `{}` to pointer `{}`",
- self.expr_ty, self.cast_ty
- ));
+ DelayDm(|| format!(
+ "strict provenance disallows casting integer `{}` to pointer `{}`",
+ self.expr_ty, self.cast_ty
+ )),
+ |lint| {
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
];
- err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
- err.help(
+ lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+ lint.help(
"if you can't comply with strict provenance and don't have a pointer with \
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
);
- err.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
new file mode 100644
index 000000000..7f76364e1
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -0,0 +1,324 @@
+use crate::coercion::CoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use crate::{FnCtxt, Inherited};
+use crate::{GeneratorTypes, UnsafetyState};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
+use rustc_hir_analysis::check::fn_maybe_err;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
+use std::cell::RefCell;
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+#[instrument(skip(inherited, body), level = "debug")]
+pub(super) fn check_fn<'a, 'tcx>(
+ inherited: &'a Inherited<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ fn_sig: ty::FnSig<'tcx>,
+ decl: &'tcx hir::FnDecl<'tcx>,
+ fn_id: hir::HirId,
+ body: &'tcx hir::Body<'tcx>,
+ can_be_generator: Option<hir::Movability>,
+ return_type_pre_known: bool,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+ // Create the function context. This is either derived from scratch or,
+ // in the case of closures, based on the outer context.
+ let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+ fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+ fcx.return_type_pre_known = return_type_pre_known;
+
+ let tcx = fcx.tcx;
+ let hir = tcx.hir();
+
+ let declared_ret_ty = fn_sig.output();
+
+ let ret_ty =
+ fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
+ declared_ret_ty,
+ body.value.hir_id,
+ decl.output.span(),
+ param_env,
+ ));
+ // If we replaced declared_ret_ty with infer vars, then we must be inferring
+ // an opaque type, so set a flag so we can improve diagnostics.
+ fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
+ fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
+
+ let span = body.value.span;
+
+ fn_maybe_err(tcx, span, fn_sig.abi);
+
+ if fn_sig.abi == Abi::RustCall {
+ let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
+
+ let err = || {
+ let item = match tcx.hir().get(fn_id) {
+ Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(header, ..), ..
+ }) => Some(header),
+ Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(header, ..),
+ ..
+ }) => Some(header),
+ // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
+ Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
+ node => bug!("Item being checked wasn't a function/closure: {:?}", node),
+ };
+
+ if let Some(header) = item {
+ tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
+ }
+ };
+
+ if fn_sig.inputs().len() != expected_args {
+ err()
+ } else {
+ // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
+ // This will probably require wide-scale changes to support a TupleKind obligation
+ // We can't resolve this without knowing the type of the param
+ if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
+ err()
+ }
+ }
+ }
+
+ if body.generator_kind.is_some() && can_be_generator.is_some() {
+ let yield_ty = fcx
+ .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+ fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+ // Resume type defaults to `()` if the generator has no argument.
+ let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+ fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+ }
+
+ GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+ // (as it's created inside the body itself, not passed in from outside).
+ let maybe_va_list = if fn_sig.c_variadic {
+ let span = body.params.last().unwrap().span;
+ let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+ let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+ Some(tcx.bound_type_of(va_list_did).subst(tcx, &[region.into()]))
+ } else {
+ None
+ };
+
+ // Add formal parameters.
+ let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+ let inputs_fn = fn_sig.inputs().iter().copied();
+ for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+ // Check the pattern.
+ let ty_span = try { inputs_hir?.get(idx)?.span };
+ fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+ // Check that argument is Sized.
+ // The check for a non-trivial pattern is a hack to avoid duplicate warnings
+ // for simple cases like `fn foo(x: Trait)`,
+ // where we would error once on the parameter as a whole, and once on the binding `x`.
+ if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
+ fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+ }
+
+ fcx.write_ty(param.hir_id, param_ty);
+ }
+
+ inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+ fcx.in_tail_expr = true;
+ if let ty::Dynamic(..) = declared_ret_ty.kind() {
+ // FIXME: We need to verify that the return type is `Sized` after the return expression has
+ // been evaluated so that we have types available for all the nodes being returned, but that
+ // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+ // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+ // while keeping the current ordering we will ignore the tail expression's type because we
+ // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+ // because we will trigger "unreachable expression" lints unconditionally.
+ // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+ // case that a newcomer might make, returning a bare trait, and in that case we populate
+ // the tail expression's type so that the suggestion will be correct, but ignore all other
+ // possible cases.
+ fcx.check_expr(&body.value);
+ fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+ } else {
+ fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+ fcx.check_return_expr(&body.value, false);
+ }
+ fcx.in_tail_expr = false;
+
+ // We insert the deferred_generator_interiors entry after visiting the body.
+ // This ensures that all nested generators appear before the entry of this generator.
+ // resolve_generator_interiors relies on this property.
+ let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+ let interior = fcx
+ .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+ fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+ let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+ Some(GeneratorTypes {
+ resume_ty,
+ yield_ty,
+ interior,
+ movability: can_be_generator.unwrap(),
+ })
+ } else {
+ None
+ };
+
+ // Finalize the return check by taking the LUB of the return types
+ // we saw and assigning it to the expected return type. This isn't
+ // really expected to fail, since the coercions would have failed
+ // earlier when trying to find a LUB.
+ let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+ let mut actual_return_ty = coercion.complete(&fcx);
+ debug!("actual_return_ty = {:?}", actual_return_ty);
+ if let ty::Dynamic(..) = declared_ret_ty.kind() {
+ // We have special-cased the case where the function is declared
+ // `-> dyn Foo` and we don't actually relate it to the
+ // `fcx.ret_coercion`, so just substitute a type variable.
+ actual_return_ty =
+ fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
+ debug!("actual_return_ty replaced with {:?}", actual_return_ty);
+ }
+
+ // HACK(oli-obk, compiler-errors): We should be comparing this against
+ // `declared_ret_ty`, but then anything uninferred would be inferred to
+ // the opaque type itself. That again would cause writeback to assume
+ // we have a recursive call site and do the sadly stabilized fallback to `()`.
+ fcx.demand_suptype(span, ret_ty, actual_return_ty);
+
+ // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+ if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
+ && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
+ {
+ check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
+ }
+
+ // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+ if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
+ && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
+ {
+ check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+ }
+
+ (fcx, gen_ty)
+}
+
+fn check_panic_info_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+ tcx.sess.err("language item required, but not found: `panic_info`");
+ return;
+ };
+
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+ return;
+ }
+
+ let arg_is_panic_info = match *inputs[0].kind() {
+ ty::Ref(region, ty, mutbl) => match *ty.kind() {
+ ty::Adt(ref adt, _) => {
+ adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+ }
+ _ => false,
+ },
+ _ => false,
+ };
+
+ if !arg_is_panic_info {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+ }
+
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no const parameters");
+ }
+}
+
+fn check_alloc_error_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+ tcx.sess.err("language item required, but not found: `alloc_layout`");
+ return;
+ };
+
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
+ return;
+ }
+
+ let arg_is_alloc_layout = match inputs[0].kind() {
+ ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+ _ => false,
+ };
+
+ if !arg_is_alloc_layout {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+ }
+
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess
+ .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 9b943b160..a5a45f75e 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -2,12 +2,11 @@
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
-use crate::astconv::AstConv;
-use crate::rustc_middle::ty::subst::Subst;
use hir::def::DefKind;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
@@ -177,24 +176,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match *expected_ty.kind() {
ty::Opaque(def_id, substs) => {
let bounds = self.tcx.bound_explicit_item_bounds(def_id);
- let sig = bounds
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(pred, span)| match pred.0.kind().skip_binder() {
+ let sig =
+ bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred
+ .kind()
+ .skip_binder()
+ {
ty::PredicateKind::Projection(proj_predicate) => self
.deduce_sig_from_projection(
- Some(span.0),
- pred.0
- .kind()
- .rebind(pred.rebind(proj_predicate).subst(self.tcx, substs)),
+ Some(span),
+ pred.kind().rebind(proj_predicate),
),
_ => None,
});
let kind = bounds
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .filter_map(|(pred, _)| match pred.0.kind().skip_binder() {
+ .0
+ .iter()
+ .filter_map(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Trait(tp) => {
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
}
@@ -642,6 +640,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
bound_vars,
);
+ // Astconv can't normalize inputs or outputs with escaping bound vars,
+ // so normalize them here, after we've wrapped them in a binder.
+ let result = self.normalize_associated_types_in(self.tcx.hir().span(hir_id), result);
let c_result = self.inh.infcx.canonicalize_response(result);
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
@@ -695,18 +696,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Opaque(def_id, substs) => self
.tcx
.bound_explicit_item_bounds(def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
+ .subst_iter_copied(self.tcx, substs)
+ .find_map(|(p, s)| get_future_output(p, s))?,
ty::Error(_) => return None,
ty::Projection(proj)
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
{
self.tcx
.bound_explicit_item_bounds(proj.item_def_id)
- .transpose_iter()
- .map(|e| e.map_bound(|e| *e).transpose_tuple2())
- .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+ .subst_iter_copied(self.tcx, proj.substs)
+ .find_map(|(p, s)| get_future_output(p, s))?
}
_ => span_bug!(
self.tcx.def_span(expr_def_id),
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index def592c46..86597a703 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -35,8 +35,7 @@
//! // and are then unable to coerce `&7i32` to `&mut i32`.
//! ```
-use crate::astconv::AstConv;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
@@ -44,6 +43,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Expr;
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
@@ -61,7 +61,7 @@ use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, DesugaringKind, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use smallvec::{smallvec, SmallVec};
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::Ref(r_b, _, mutbl_b) => {
return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
}
+ ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+ return self.coerce_dyn_star(a, b, predicates, region);
+ }
_ => {}
}
@@ -702,7 +705,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Object safety violations or miscellaneous.
Err(err) => {
- self.report_selection_error(obligation.clone(), &obligation, &err, false);
+ self.err_ctxt().report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &err,
+ false,
+ );
// Treat this like an obligation and follow through
// with the unsizing - the lack of a coercion should
// be silent, as it causes a type mismatch later.
@@ -740,6 +748,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Ok(coercion)
}
+ fn coerce_dyn_star(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ b_region: ty::Region<'tcx>,
+ ) -> CoerceResult<'tcx> {
+ if !self.tcx.features().dyn_star {
+ return Err(TypeError::Mismatch);
+ }
+
+ if let ty::Dynamic(a_data, _, _) = a.kind()
+ && let ty::Dynamic(b_data, _, _) = b.kind()
+ {
+ if a_data.principal_def_id() == b_data.principal_def_id() {
+ return self.unify_and(a, b, |_| vec![]);
+ } else if !self.tcx().features().trait_upcasting {
+ let mut err = feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::trait_upcasting,
+ self.cause.span,
+ &format!(
+ "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
+ ),
+ );
+ err.emit();
+ }
+ }
+
+ // Check the obligations of the cast -- for example, when casting
+ // `usize` to `dyn* Clone + 'static`:
+ let obligations = predicates
+ .iter()
+ .map(|predicate| {
+ // For each existential predicate (e.g., `?Self: Clone`) substitute
+ // the type of the expression (e.g., `usize` in our example above)
+ // and then require that the resulting predicate (e.g., `usize: Clone`)
+ // holds (it does).
+ let predicate = predicate.with_self_ty(self.tcx, a);
+ Obligation::new(self.cause.clone(), self.param_env, predicate)
+ })
+ // Enforce the region bound (e.g., `usize: 'static`, in our example).
+ .chain([Obligation::new(
+ self.cause.clone(),
+ self.param_env,
+ self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(a, b_region),
+ ))),
+ )])
+ .collect();
+
+ Ok(InferOk {
+ value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+ obligations,
+ })
+ }
+
fn coerce_from_safe_fn<F, G>(
&self,
a: Ty<'tcx>,
@@ -1549,7 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
}
_ => {
- err = fcx.report_mismatched_types(
+ err = fcx.err_ctxt().report_mismatched_types(
cause,
expected,
found,
@@ -1629,7 +1694,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expression: Option<&'tcx hir::Expr<'tcx>>,
blk_id: Option<hir::HirId>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
+ let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
let mut pointing_at_return_type = false;
let mut fn_output = None;
@@ -1683,7 +1748,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expected,
found,
can_suggest,
- fcx.tcx.hir().local_def_id_to_hir_id(fcx.tcx.hir().get_parent_item(id)),
+ fcx.tcx.hir().get_parent_item(id).into(),
);
}
if !pointing_at_return_type {
@@ -1692,7 +1757,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
let parent_id = fcx.tcx.hir().get_parent_item(id);
- let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
+ let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
@@ -1704,7 +1769,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
expected,
found,
id,
- fcx.tcx.hir().local_def_id_to_hir_id(parent_id),
+ parent_id.into(),
);
}
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index e1d55ff82..16febfc46 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1,21 +1,20 @@
-use crate::check::FnCtxt;
-use rustc_infer::infer::InferOk;
-use rustc_middle::middle::stability::EvalResult;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::ObligationCause;
-
+use crate::FnCtxt;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
+use rustc_infer::infer::InferOk;
use rustc_middle::lint::in_external_macro;
+use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCause;
use super::method::probe;
@@ -32,17 +31,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: Option<TypeError<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr, error);
- self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
- self.suggest_compatible_variants(err, expr, expected, expr_ty);
- self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
- if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
- return;
- }
- self.suggest_no_capture_closure(err, expected, expr_ty);
- self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
- self.suggest_missing_parentheses(err, expr);
- self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
- self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
+
+ // Use `||` to give these suggestions a precedence
+ let _ = self.suggest_missing_parentheses(err, expr)
+ || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
+ || self.suggest_compatible_variants(err, expr, expected, expr_ty)
+ || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
+ || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_no_capture_closure(err, expected, expr_ty)
+ || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
+ || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_into(err, expr, expr_ty, expected);
+
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@@ -77,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
}
}
@@ -107,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.register_predicates(obligations);
None
}
- Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
+ Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
}
}
@@ -151,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr = expr.peel_drop_temps();
let cause = self.misc(expr.span);
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
- let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
+ let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
let is_insufficiently_polymorphic =
matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
@@ -286,7 +287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
if let ty::Adt(expected_adt, substs) = expected.kind() {
if let hir::ExprKind::Field(base, ident) = expr.kind {
let base_ty = self.typeck_results.borrow().expr_ty(base);
@@ -299,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"",
Applicability::MaybeIncorrect,
);
- return
+ return true;
}
}
@@ -338,7 +339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
vec!["None", "Some(())"]
} else {
- return;
+ return false;
};
if let Some(indent) =
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@@ -358,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
- return;
+ return true;
}
}
}
@@ -375,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
- sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+ sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
// Skip suggestions for unstable public fields (for example `Pin::pointer`)
&& matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
@@ -417,6 +418,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::def::CtorKind::Const => unreachable!(),
};
+ // Suggest constructor as deep into the block tree as possible.
+ // This fixes https://github.com/rust-lang/rust/issues/101065,
+ // and also just helps make the most minimal suggestions.
+ let mut expr = expr;
+ while let hir::ExprKind::Block(block, _) = &expr.kind
+ && let Some(expr_) = &block.expr
+ {
+ expr = expr_
+ }
+
vec![
(expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
(expr.span.shrink_to_hi(), close.to_owned()),
@@ -435,6 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions_for(&**variant, *ctor_kind, *field_name),
Applicability::MaybeIncorrect,
);
+ return true;
}
_ => {
// More than one matching variant.
@@ -450,9 +462,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
Applicability::MaybeIncorrect,
);
+ return true;
}
}
}
+
+ false
}
fn suggest_non_zero_new_unwrap(
@@ -461,19 +476,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
- let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
+ let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
(adt, "")
}
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
ty::Adt(adt, _) => (adt, ".unwrap()"),
- _ => return,
+ _ => return false,
};
let map = [
@@ -492,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some((s, _)) = map
.iter()
.find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
- else { return };
+ else { return false; };
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
@@ -504,6 +519,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
],
Applicability::MaybeIncorrect,
);
+
+ true
}
pub fn get_conversion_methods(
@@ -513,24 +530,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
checked_ty: Ty<'tcx>,
hir_id: hir::HirId,
) -> Vec<AssocItem> {
- let mut methods =
- self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
- methods.retain(|m| {
- self.has_only_self_parameter(m)
- && self
- .tcx
- // This special internal attribute is used to permit
- // "identity-like" conversion methods to be suggested here.
- //
- // FIXME (#46459 and #46460): ideally
- // `std::convert::Into::into` and `std::borrow:ToOwned` would
- // also be `#[rustc_conversion_suggestion]`, if not for
- // method-probing false-positives and -negatives (respectively).
- //
- // FIXME? Other potential candidate methods: `as_ref` and
- // `as_mut`?
- .has_attr(m.def_id, sym::rustc_conversion_suggestion)
- });
+ let methods = self.probe_for_return_type(
+ span,
+ probe::Mode::MethodCall,
+ expected,
+ checked_ty,
+ hir_id,
+ |m| {
+ self.has_only_self_parameter(m)
+ && self
+ .tcx
+ // This special internal attribute is used to permit
+ // "identity-like" conversion methods to be suggested here.
+ //
+ // FIXME (#46459 and #46460): ideally
+ // `std::convert::Into::into` and `std::borrow:ToOwned` would
+ // also be `#[rustc_conversion_suggestion]`, if not for
+ // method-probing false-positives and -negatives (respectively).
+ //
+ // FIXME? Other potential candidate methods: `as_ref` and
+ // `as_mut`?
+ .has_attr(m.def_id, sym::rustc_conversion_suggestion)
+ },
+ );
methods
}
@@ -697,7 +719,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
- ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
+ ) -> Option<(
+ Span,
+ String,
+ String,
+ Applicability,
+ bool, /* verbose */
+ bool, /* suggest `&` or `&mut` type annotation */
+ )> {
let sess = self.sess();
let sp = expr.span;
@@ -729,6 +758,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -743,6 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"b".to_string(),
Applicability::MachineApplicable,
true,
+ false,
));
}
}
@@ -800,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg.2,
Applicability::MachineApplicable,
false,
+ false,
));
}
@@ -827,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&mut {sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
hir::Mutability::Not => (
sp,
@@ -834,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{prefix}&{sugg_expr}"),
Applicability::MachineApplicable,
false,
+ false,
),
});
}
@@ -863,6 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true
));
}
return None;
@@ -876,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
String::new(),
Applicability::MachineApplicable,
true,
+ true,
));
}
}
@@ -942,6 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
src,
applicability,
true,
+ false,
));
}
}
@@ -982,6 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable
},
true,
+ false,
));
}
@@ -1033,6 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestion,
Applicability::MachineApplicable,
true,
+ false,
));
}
}
diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_hir_typeck/src/diverges.rs
index 963a93a95..963a93a95 100644
--- a/compiler/rustc_typeck/src/check/diverges.rs
+++ b/compiler/rustc_hir_typeck/src/diverges.rs
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
new file mode 100644
index 000000000..175037f9b
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -0,0 +1,126 @@
+//! Errors emitted by `rustc_hir_analysis`.
+use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_middle::ty::Ty;
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_field_multiply_specified_in_initializer, code = "E0062")]
+pub struct FieldMultiplySpecifiedInInitializer {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(previous_use_label)]
+ pub prev_span: Span,
+ pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_stmt_outside_of_fn_body, code = "E0572")]
+pub struct ReturnStmtOutsideOfFnBody {
+ #[primary_span]
+ pub span: Span,
+ #[label(encl_body_label)]
+ pub encl_body_span: Option<Span>,
+ #[label(encl_fn_label)]
+ pub encl_fn_span: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_yield_expr_outside_of_generator, code = "E0627")]
+pub struct YieldExprOutsideOfGenerator {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_struct_expr_non_exhaustive, code = "E0639")]
+pub struct StructExprNonExhaustive {
+ #[primary_span]
+ pub span: Span,
+ pub what: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_method_call_on_unknown_type, code = "E0699")]
+pub struct MethodCallOnUnknownType {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_functional_record_update_on_non_struct, code = "E0436")]
+pub struct FunctionalRecordUpdateOnNonStruct {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_address_of_temporary_taken, code = "E0745")]
+pub struct AddressOfTemporaryTaken {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum AddReturnTypeSuggestion {
+ #[suggestion(
+ hir_analysis_add_return_type_add,
+ code = "-> {found} ",
+ applicability = "machine-applicable"
+ )]
+ Add {
+ #[primary_span]
+ span: Span,
+ found: String,
+ },
+ #[suggestion(
+ hir_analysis_add_return_type_missing_here,
+ code = "-> _ ",
+ applicability = "has-placeholders"
+ )]
+ MissingHere {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub enum ExpectedReturnTypeLabel<'tcx> {
+ #[label(hir_analysis_expected_default_return_type)]
+ Unit {
+ #[primary_span]
+ span: Span,
+ },
+ #[label(hir_analysis_expected_return_type)]
+ Other {
+ #[primary_span]
+ span: Span,
+ expected: Ty<'tcx>,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_parentheses_in_range, code = "E0689")]
+pub struct MissingParentheseInRange {
+ #[primary_span]
+ #[label(hir_analysis_missing_parentheses_in_range)]
+ pub span: Span,
+ pub ty_str: String,
+ pub method_name: String,
+ #[subdiagnostic]
+ pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion_verbose(
+ hir_analysis_add_missing_parentheses_in_range,
+ applicability = "maybe-incorrect"
+)]
+pub struct AddMissingParenthesesInRange {
+ pub func_name: String,
+ #[suggestion_part(code = "(")]
+ pub left: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index e9e810344..e9e810344 100644
--- a/compiler/rustc_typeck/src/check/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 93b008500..9fde62a81 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2,23 +2,22 @@
//!
//! See `mod.rs` for more context on type checking in general.
-use crate::astconv::AstConv as _;
-use crate::check::cast::{self, CastCheckResult};
-use crate::check::coercion::CoerceMany;
-use crate::check::fatally_break_rust;
-use crate::check::method::SelfSource;
-use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
-use crate::check::{
- report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
- TupleArgumentsFlag::DontTupleArguments,
-};
+use crate::cast;
+use crate::coercion::CoerceMany;
+use crate::coercion::DynamicCoerceMany;
+use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use crate::errors::{
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
YieldExprOutsideOfGenerator,
};
+use crate::fatally_break_rust;
+use crate::method::SelfSource;
use crate::type_error_struct;
-
-use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
+use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
+use crate::{
+ report_unexpected_variant_res, BreakableCtxt, Diverges, FnCtxt, Needs,
+ TupleArgumentsFlag::DontTupleArguments,
+};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -32,6 +31,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Closure, ExprKind, HirId, QPath};
+use rustc_hir_analysis::astconv::AstConv as _;
+use rustc_hir_analysis::check::ty_kind_suggestion;
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::InferOk;
@@ -41,6 +42,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
@@ -394,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(sp) =
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
- tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
err.emit();
oprnd_t = tcx.ty_error();
@@ -541,7 +543,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// been resolved or we errored. This is important as we can only check transmute
// on concrete types, but the output type may not be known yet (it would only
// be known if explicitly specified via turbofish).
- self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span));
+ self.deferred_transmute_checks.borrow_mut().push((from, to, expr.hir_id));
}
if !tcx.features().unsized_fn_params {
// We want to remove some Sized bounds from std functions,
@@ -752,7 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: hir::ImplItemKind::Fn(..),
span: encl_fn_span,
..
- })) = self.tcx.hir().find_by_def_id(encl_item_id)
+ })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
{
// We are inside a function body, so reporting "return statement
// outside of function body" needs an explanation.
@@ -761,7 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this didn't hold, we would not have to report an error in
// the first place.
- assert_ne!(encl_item_id, encl_body_owner_id);
+ assert_ne!(encl_item_id.def_id, encl_body_owner_id);
let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
let encl_body = self.tcx.hir().body(encl_body_id);
@@ -881,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
+ // FIXME: Make this use Diagnostic once error codes can be dynamically set.
let mut err = self.tcx.sess.struct_span_err_with_code(
op_span,
"invalid left-hand side of assignment",
@@ -1044,6 +1046,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let rhs_ty = self.check_expr(&rhs);
let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) {
(Applicability::MachineApplicable, true)
+ } else if let ExprKind::Binary(
+ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ _,
+ rhs_expr,
+ ) = lhs.kind
+ {
+ // if x == 1 && y == 2 { .. }
+ // +
+ let actual_lhs_ty = self.check_expr(&rhs_expr);
+ (Applicability::MaybeIncorrect, self.can_coerce(rhs_ty, actual_lhs_ty))
+ } else if let ExprKind::Binary(
+ Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ lhs_expr,
+ _,
+ ) = rhs.kind
+ {
+ // if x == 1 && y == 2 { .. }
+ // +
+ let actual_rhs_ty = self.check_expr(&lhs_expr);
+ (Applicability::MaybeIncorrect, self.can_coerce(actual_rhs_ty, lhs_ty))
} else {
(Applicability::MaybeIncorrect, false)
};
@@ -1066,9 +1088,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if eq {
err.span_suggestion_verbose(
- span,
+ span.shrink_to_hi(),
"you might have meant to compare for equality",
- "==",
+ '=',
applicability,
);
}
@@ -1109,11 +1131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- self.check_lhs_assignable(lhs, "E0070", span, |err| {
- let rhs_ty = self.check_expr(&rhs);
- suggest_deref_binop(err, rhs_ty);
- });
-
// This is (basically) inlined `check_expr_coercable_to_type`, but we want
// to suggest an additional fixup here in `suggest_deref_binop`.
let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
@@ -1124,6 +1141,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diag.emit();
}
+ self.check_lhs_assignable(lhs, "E0070", span, |err| {
+ if let Some(rhs_ty) = self.typeck_results.borrow().expr_ty_opt(rhs) {
+ suggest_deref_binop(err, rhs_ty);
+ }
+ });
+
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
if lhs_ty.references_error() || rhs_ty.references_error() {
@@ -1249,9 +1272,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
- match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
- CastCheckResult::Ok => t_cast,
- CastCheckResult::Deferred(cast_check) => {
+ match cast::CastCheck::new(
+ self,
+ e,
+ t_expr,
+ t_cast,
+ t.span,
+ expr.span,
+ self.param_env.constness(),
+ ) {
+ Ok(cast_check) => {
debug!(
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
t_cast, t_expr, cast_check,
@@ -1259,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
deferred_cast_checks.push(cast_check);
t_cast
}
- CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
+ Err(_) => self.tcx.ty_error(),
}
}
}
@@ -1341,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a new function context.
let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
- crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+ crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
@@ -1640,13 +1670,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(_) => {
// This should never happen, since we're just subtyping the
// remaining_fields, but it's fine to emit this, I guess.
- self.report_mismatched_types(
- &cause,
- target_ty,
- fru_ty,
- FieldMisMatch(variant.name, ident.name),
- )
- .emit();
+ self.err_ctxt()
+ .report_mismatched_types(
+ &cause,
+ target_ty,
+ fru_ty,
+ FieldMisMatch(variant.name, ident.name),
+ )
+ .emit();
}
}
}
@@ -1933,7 +1964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.set_tainted_by_errors();
return;
}
- let mut err = self.type_error_struct_with_diag(
+ let mut err = self.err_ctxt().type_error_struct_with_diag(
field.ident.span,
|actual| match ty.kind() {
ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!(
@@ -2338,7 +2369,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
def.non_enum_variant().fields.iter().any(|field| {
field.ident(self.tcx) == ident
- && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
+ && field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
})
} else if let ty::Tuple(tys) = output_ty.kind()
&& let Ok(idx) = ident.as_str().parse::<usize>()
@@ -2863,14 +2894,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
-
-pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
- Some(match ty.kind() {
- ty::Bool => "true",
- ty::Char => "'a'",
- ty::Int(_) | ty::Uint(_) => "42",
- ty::Float(_) => "3.14159",
- ty::Error(_) | ty::Never => return None,
- _ => "value",
- })
-}
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index f483342b4..fce2a5888 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -89,15 +89,6 @@ enum ConsumeMode {
Move,
}
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum MutateMode {
- Init,
- /// Example: `x = y`
- JustWrite,
- /// Example: `x += y`
- WriteAndRead,
-}
-
/// The ExprUseVisitor type
///
/// This is the code that actually walks the tree.
@@ -134,7 +125,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
/// - `typeck_results` --- typeck results for the code being analyzed
pub fn new(
delegate: &'a mut (dyn Delegate<'tcx> + 'a),
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
body_owner: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -583,7 +574,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
for adjustment in adjustments {
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
match adjustment.kind {
- adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
+ adjustment::Adjust::NeverToAny
+ | adjustment::Adjust::Pointer(_)
+ | adjustment::Adjust::DynStar => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
self.delegate_consume(&place_with_id, place_with_id.hir_id);
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 4059b3403..747ecb036 100644
--- a/compiler/rustc_typeck/src/check/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -1,4 +1,4 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_data_structures::{
fx::{FxHashMap, FxHashSet},
graph::WithSuccessors,
@@ -72,7 +72,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
//
// - Unconstrained ints are replaced with `i32`.
//
- // - Unconstrained floats are replaced with with `f64`.
+ // - Unconstrained floats are replaced with `f64`.
//
// - Non-numerics may get replaced with `()` or `!`, depending on
// how they were categorized by `calculate_diverging_fallback`
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index a40478db9..6a1cffe3e 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,12 +1,7 @@
-use crate::astconv::{
- AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
- GenericArgCountResult, IsMethodCall, PathSeg,
-};
-use crate::check::callee::{self, DeferredCallResolution};
-use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::rvalue_scopes;
-use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-
+use crate::callee::{self, DeferredCallResolution};
+use crate::method::{self, MethodCallee, SelfSource};
+use crate::rvalue_scopes;
+use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@@ -15,26 +10,28 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::astconv::{
+ AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+ GenericArgCountResult, IsMethodCall, PathSeg,
+};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{
- self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
ToPredicate, Ty, UserType,
};
+use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
};
@@ -60,17 +57,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
- self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
- let msg = format!("unreachable {}", kind);
- lint.build(&msg)
- .span_label(span, &msg)
- .span_label(
+ let msg = format!("unreachable {}", kind);
+ self.tcx().struct_span_lint_hir(
+ lint::builtin::UNREACHABLE_CODE,
+ id,
+ span,
+ &msg,
+ |lint| {
+ lint.span_label(span, &msg).span_label(
orig_span,
custom_note
.unwrap_or("any code following this expression is unreachable"),
)
- .emit();
- })
+ },
+ )
}
}
}
@@ -90,14 +90,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) -> Ty<'tcx> {
// No Infer()? Nothing needs doing.
- if !ty.has_infer_types_or_consts() {
+ if !ty.has_non_region_infer() {
debug!("no inference var, nothing needs doing");
return ty;
}
// If `ty` is a type variable, see whether we already know what it is.
ty = self.resolve_vars_if_possible(ty);
- if !ty.has_infer_types_or_consts() {
+ if !ty.has_non_region_infer() {
debug!(?ty);
return ty;
}
@@ -489,18 +489,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
match length {
&hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
- hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+ hir::ArrayLen::Body(anon_const) => {
+ let const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+ let span = self.tcx.hir().span(anon_const.hir_id);
+ let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+ self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
+ self.normalize_associated_types_in(span, c)
+ }
}
}
- pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
- let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
- let span = self.tcx.hir().span(ast_c.hir_id);
- let c = ty::Const::from_anon_const(self.tcx, const_def_id);
- self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
- self.normalize_associated_types_in(span, c)
- }
-
pub fn const_arg_to_const(
&self,
ast_c: &hir::AnonConst,
@@ -559,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
pub fn register_wf_obligation(
&self,
- arg: subst::GenericArg<'tcx>,
+ arg: ty::GenericArg<'tcx>,
span: Span,
code: traits::ObligationCauseCode<'tcx>,
) {
@@ -604,9 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (body_id, interior, kind) in generators.drain(..) {
self.select_obligations_where_possible(false, |_| {});
- crate::check::generator_interior::resolve_interior(
- self, def_id, body_id, interior, kind,
- );
+ crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
}
}
@@ -616,7 +612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+ self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@@ -630,7 +626,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
- self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
+ self.err_ctxt().report_fulfillment_errors(
+ &result,
+ self.inh.body_id,
+ fallback_has_occurred,
+ );
}
}
@@ -1271,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut self,
param: &ty::GenericParamDef,
arg: &GenericArg<'_>,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
match (&param.kind, arg) {
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
<dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
@@ -1295,10 +1295,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn inferred_kind(
&mut self,
- substs: Option<&[subst::GenericArg<'tcx>]>,
+ substs: Option<&[ty::GenericArg<'tcx>]>,
param: &ty::GenericParamDef,
infer_args: bool,
- ) -> subst::GenericArg<'tcx> {
+ ) -> ty::GenericArg<'tcx> {
let tcx = self.fcx.tcx();
match param.kind {
GenericParamDefKind::Lifetime => {
@@ -1410,7 +1410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
}
- #[instrument(level = "debug", skip(self, code, span, def_id, substs))]
+ #[instrument(level = "debug", skip(self, code, span, substs))]
fn add_required_obligations_with_code(
&self,
span: Span,
@@ -1418,15 +1418,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
substs: SubstsRef<'tcx>,
code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>,
) {
+ let param_env = self.param_env;
+
+ let remap = match self.tcx.def_kind(def_id) {
+ // Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
+ // `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
+ // Therefore we have to remap the param env here to be non-const.
+ hir::def::DefKind::AssocConst => true,
+ hir::def::DefKind::AssocFn
+ if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
+ {
+ // N.B.: All callsites to this function involve checking a path expression.
+ //
+ // When instantiating a trait method as a function item, it does not actually matter whether
+ // the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
+ // `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
+ // check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
+ // `const fn` pointer.
+ //
+ // FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
+ // `~const FnOnce` or can be coerced to `const fn` pointer.
+ true
+ }
+ _ => false,
+ };
let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
- for obligation in traits::predicates_for_generics(
+ for mut obligation in traits::predicates_for_generics(
|idx, predicate_span| {
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
},
- self.param_env,
+ param_env,
bounds,
) {
+ if remap {
+ obligation = obligation.without_const(self.tcx);
+ }
self.register_predicate(obligation);
}
}
@@ -1440,7 +1467,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty
} else {
if !self.is_tainted_by_errors() {
- self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
+ self.err_ctxt()
+ .emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
.emit();
}
let err = self.tcx.ty_error();
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index fc83994ca..fc83994ca 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 311fcaada..8e0fcb56c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,19 +1,13 @@
-use crate::astconv::AstConv;
-use crate::check::coercion::CoerceMany;
-use crate::check::fn_ctxt::arg_matrix::{
- ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx,
+use crate::coercion::CoerceMany;
+use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
+use crate::gather_locals::Declaration;
+use crate::method::MethodCallee;
+use crate::Expectation::*;
+use crate::TupleArgumentsFlag::*;
+use crate::{
+ struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs,
+ TupleArgumentsFlag,
};
-use crate::check::gather_locals::Declaration;
-use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::check::method::MethodCallee;
-use crate::check::Expectation::*;
-use crate::check::TupleArgumentsFlag::*;
-use crate::check::{
- potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
- LocalTy, Needs, TupleArgumentsFlag,
-};
-use crate::structured_errors::StructuredDiagnostic;
-
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
@@ -21,6 +15,10 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{ExprKind, Node, QPath};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
+use rustc_hir_analysis::check::potentially_plural_count;
+use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -35,23 +33,34 @@ use rustc_span::{self, sym, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
+use std::mem;
use std::ops::ControlFlow;
use std::slice;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub(in super::super) fn check_casts(&self) {
- let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+ pub(in super::super) fn check_casts(&mut self) {
+ // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
+ // when writing to `self.param_env`.
+ let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut());
+
debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
for cast in deferred_cast_checks.drain(..) {
+ let prev_env = self.param_env;
+ self.param_env = self.param_env.with_constness(cast.constness);
+
cast.check(self);
+
+ self.param_env = prev_env;
}
+
+ *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
}
pub(in super::super) fn check_transmutes(&self) {
let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
- for (from, to, span) in deferred_transmute_checks.drain(..) {
- self.check_transmute(span, from, to);
+ for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
+ self.check_transmute(from, to, hir_id);
}
}
@@ -63,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let get_operand_ty = |expr| {
let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.resolve_vars_if_possible(ty);
- if ty.has_infer_types_or_consts() {
+ if ty.has_non_region_infer() {
assert!(self.is_tainted_by_errors());
self.tcx.ty_error()
} else {
@@ -391,7 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
cast_ty: &str,
) {
- use crate::structured_errors::MissingCastForVariadicArg;
+ use rustc_hir_analysis::structured_errors::MissingCastForVariadicArg;
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
}
@@ -650,7 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tys.len() == 1 {
// A tuple wrap suggestion actually occurs within,
// so don't do anything special here.
- err = self.report_and_explain_type_error(
+ err = self.err_ctxt().report_and_explain_type_error(
TypeTrace::types(
&self.misc(*lo),
true,
@@ -742,7 +751,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = &self.misc(provided_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308(_)) {
- self.report_and_explain_type_error(trace, *e).emit();
+ self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
return true;
}
false
@@ -766,7 +775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx];
let cause = &self.misc(provided_arg_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
- let mut err = self.report_and_explain_type_error(trace, *err);
+ let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err);
self.emit_coerce_suggestions(
&mut err,
&provided_args[*provided_idx],
@@ -840,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = &self.misc(provided_span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error {
- self.note_type_err(
+ self.err_ctxt().note_type_err(
&mut err,
&trace.cause,
None,
@@ -1199,7 +1208,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => bug!("unexpected type: {:?}", ty),
},
Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
- | Res::SelfTy { .. } => match ty.kind() {
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. } => match ty.kind() {
ty::Adt(adt, substs) if !adt.is_enum() => {
Some((adt.non_enum_variant(), adt.did(), substs))
}
@@ -1473,7 +1483,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
if !self.consider_removing_semicolon(blk, expected_ty, err) {
- self.consider_returning_binding(blk, expected_ty, err);
+ self.err_ctxt().consider_returning_binding(
+ blk,
+ expected_ty,
+ err,
+ );
}
if expected_ty == self.tcx.types.bool {
// If this is caused by a missing `let` in a `while let`,
@@ -1543,7 +1557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
- let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
+ let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id).def_id);
match node {
Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
@@ -1559,7 +1573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
- let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id));
+ let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 0e22971d3..0c600daf4 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -6,13 +6,13 @@ mod suggestions;
pub use _impl::*;
pub use suggestions::*;
-use crate::astconv::AstConv;
-use crate::check::coercion::DynamicCoerceMany;
-use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
-
+use crate::coercion::DynamicCoerceMany;
+use crate::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer;
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::subst::GenericArgKind;
@@ -35,7 +35,7 @@ use std::ops::Deref;
///
/// See [`ItemCtxt`]'s docs for more.
///
-/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
/// [`InferCtxt`]: infer::InferCtxt
pub struct FnCtxt<'a, 'tcx> {
pub(super) body_id: hir::HirId,
@@ -117,7 +117,7 @@ pub struct FnCtxt<'a, 'tcx> {
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
- pub(super) inh: &'a Inherited<'a, 'tcx>,
+ pub(super) inh: &'a Inherited<'tcx>,
/// True if the function or closure's return type is known before
/// entering the function/closure, i.e. if the return type is
@@ -131,7 +131,7 @@ pub struct FnCtxt<'a, 'tcx> {
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn new(
- inh: &'a Inherited<'a, 'tcx>,
+ inh: &'a Inherited<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
) -> FnCtxt<'a, 'tcx> {
@@ -168,13 +168,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.tcx.sess
}
+ /// Creates an `TypeErrCtxt` with a reference to the in-progress
+ /// `TypeckResults` which is used for diagnostics.
+ /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`.
+ ///
+ /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
+ pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
+ TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+ }
+
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx.sess.err_count() > self.err_count_on_creation
}
}
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
- type Target = Inherited<'a, 'tcx>;
+ type Target = Inherited<'tcx>;
fn deref(&self) -> &Self::Target {
&self.inh
}
@@ -276,7 +285,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
self,
- self.tcx,
span,
item_def_id,
item_segment,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index ee0ad7b5d..4db9c56f9 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,9 +1,7 @@
use super::FnCtxt;
-use crate::astconv::AstConv;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
-use hir::def_id::DefId;
-use rustc_ast::util::parser::ExprPrecedence;
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
@@ -11,13 +9,16 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
+use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::{self, TyCtxtInferExt};
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::DefIdOrName;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -64,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// When encountering an fn-like type, try accessing the output of the type
- /// // and suggesting calling it if it satisfies a predicate (i.e. if the
+ /// and suggesting calling it if it satisfies a predicate (i.e. if the
/// output has a method or a field):
/// ```compile_fail,E0308
/// fn foo(x: usize) -> usize { x }
@@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if ty.is_suggestable(self.tcx, false) {
format!("/* {ty} */")
} else {
- "".to_string()
+ "/* value */".to_string()
}
})
.collect::<Vec<_>>()
@@ -101,10 +102,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = match def_id_or_name {
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
- DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
- DefKind::Ctor(CtorOf::Variant, _) => {
- "instantiate this tuple variant".to_string()
- }
+ DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
+ DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
kind => format!("call this {}", kind.descr(def_id)),
},
DefIdOrName::Name(name) => format!("call this {name}"),
@@ -138,7 +137,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg,
applicability,
);
-
return true;
}
false
@@ -327,9 +325,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
- ) {
+ ) -> bool {
let expr = expr.peel_blocks();
- if let Some((sp, msg, suggestion, applicability, verbose)) =
+ if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
self.check_ref(expr, found, expected)
{
if verbose {
@@ -337,12 +335,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(sp, &msg, suggestion, applicability);
}
+ if annotation {
+ let suggest_annotation = match expr.peel_drop_temps().kind {
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+ _ => return true,
+ };
+ let mut tuple_indexes = Vec::new();
+ let mut expr_id = expr.hir_id;
+ for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) {
+ match node {
+ Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
+ tuple_indexes.push(
+ subs.iter()
+ .enumerate()
+ .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
+ .unwrap()
+ .0,
+ );
+ expr_id = parent_id;
+ }
+ Node::Local(local) => {
+ if let Some(mut ty) = local.ty {
+ while let Some(index) = tuple_indexes.pop() {
+ match ty.kind {
+ TyKind::Tup(tys) => ty = &tys[index],
+ _ => return true,
+ }
+ }
+ let annotation_span = ty.span;
+ err.span_suggestion(
+ annotation_span.with_hi(annotation_span.lo()),
+ format!("alternatively, consider changing the type annotation"),
+ suggest_annotation,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ break;
+ }
+ _ => break,
+ }
+ }
+ }
+ return true;
+ } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
+ return true;
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
&& let ty::FnDef(def_id, ..) = &found.kind()
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
{
err.span_label(sp, format!("{found} defined here"));
- } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ return true;
+ } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ return true;
+ } else {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
if !methods.is_empty() {
let mut suggestions = methods.iter()
@@ -393,6 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions,
Applicability::MaybeIncorrect,
);
+ return true;
}
} else if let ty::Adt(found_adt, found_substs) = found.kind()
&& self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
@@ -417,9 +464,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
Applicability::MaybeIncorrect,
);
+ return true;
}
}
}
+
+ false
}
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
@@ -430,13 +480,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
- ) {
+ ) -> bool {
if self.tcx.hir().is_inside_const_context(expr.hir_id) {
// Do not suggest `Box::new` in const context.
- return;
+ return false;
}
if !expected.is_box() || found.is_box() {
- return;
+ return false;
}
let boxed_found = self.tcx.mk_box(found);
if self.can_coerce(boxed_found, expected) {
@@ -454,6 +504,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
https://doc.rust-lang.org/std/boxed/index.html",
);
+ true
+ } else {
+ false
}
}
@@ -464,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut Diagnostic,
expected: Ty<'tcx>,
found: Ty<'tcx>,
- ) {
+ ) -> bool {
if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
// Report upto four upvars being captured to reduce the amount error messages
@@ -488,8 +541,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
multi_span,
"closures can only be coerced to `fn` types if they do not capture any variables"
);
+ return true;
}
}
+ false
}
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@@ -860,18 +915,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
let ty = self.normalize_associated_types_in(expr.span, ty);
let ty = match self.tcx.asyncness(fn_id.owner) {
- hir::IsAsync::Async => self
- .tcx
- .infer_ctxt()
- .enter(|infcx| {
- infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+ hir::IsAsync::Async => {
+ let infcx = self.tcx.infer_ctxt().build();
+ infcx
+ .get_impl_future_output_ty(ty)
+ .unwrap_or_else(|| {
span_bug!(
fn_decl.output.span(),
"failed to get output type of async function"
)
})
- })
- .skip_binder(),
+ .skip_binder()
+ }
hir::IsAsync::NotAsync => ty,
};
if self.can_coerce(found, ty) {
@@ -891,11 +946,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
- ) {
+ ) -> bool {
let sp = self.tcx.sess.source_map().start_point(expr.span);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
- self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+ true
+ } else {
+ false
}
}
@@ -908,7 +966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut expr: &hir::Expr<'_>,
mut expr_ty: Ty<'tcx>,
mut expected_ty: Ty<'tcx>,
- ) {
+ ) -> bool {
loop {
match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
(
@@ -922,9 +980,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
(hir::ExprKind::Block(blk, _), _, _) => {
self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty);
- break;
+ break true;
}
- _ => break,
+ _ => break false,
}
}
}
@@ -935,11 +993,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
- ) {
- let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
- let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
+ ) -> bool {
+ let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; };
+ let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; };
if adt_def != expected_adt_def {
- return;
+ return false;
}
let mut suggest_copied_or_cloned = || {
@@ -958,6 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".copied()",
Applicability::MachineApplicable,
);
+ return true;
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
@@ -975,8 +1034,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".cloned()",
Applicability::MachineApplicable,
);
+ return true;
}
}
+ false
};
if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
@@ -984,12 +1045,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check that the error types are equal
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
{
- suggest_copied_or_cloned();
+ return suggest_copied_or_cloned();
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
&& adt_def.did() == option_did
{
- suggest_copied_or_cloned();
+ return suggest_copied_or_cloned();
}
+
+ false
+ }
+
+ pub(crate) fn suggest_into(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ let expr = expr.peel_blocks();
+
+ // We have better suggestions for scalar interconversions...
+ if expr_ty.is_scalar() && expected_ty.is_scalar() {
+ return false;
+ }
+
+ // Don't suggest turning a block into another type (e.g. `{}.into()`)
+ if matches!(expr.kind, hir::ExprKind::Block(..)) {
+ return false;
+ }
+
+ // We'll later suggest `.as_ref` when noting the type error,
+ // so skip if we will suggest that instead.
+ if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
+ return false;
+ }
+
+ if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
+ && self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
+ self.misc(expr.span),
+ self.param_env,
+ ty::Binder::dummy(ty::TraitRef {
+ def_id: into_def_id,
+ substs: self.tcx.mk_substs_trait(expr_ty, &[expected_ty.into()]),
+ })
+ .to_poly_trait_predicate()
+ .to_predicate(self.tcx),
+ ))
+ {
+ let sugg = if expr.precedence().order() >= PREC_POSTFIX {
+ vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
+ } else {
+ vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
+ };
+ diag.multipart_suggestion(
+ format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
+ sugg,
+ Applicability::MaybeIncorrect
+ );
+ return true;
+ }
+
+ false
}
/// Suggest wrapping the block in square brackets instead of curly braces
@@ -1110,7 +1226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty: Ty<'tcx>,
err: &mut Diagnostic,
) -> bool {
- if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
+ if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
if let StatementAsExpression::NeedsBoxing = boxed {
err.span_suggestion_verbose(
span_semi,
@@ -1121,7 +1237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion_short(
span_semi,
- "remove this semicolon",
+ "remove this semicolon to return this value",
"",
Applicability::MachineApplicable,
);
@@ -1132,8 +1248,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
-
-pub enum DefIdOrName {
- DefId(DefId),
- Name(&'static str),
-}
diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 8f34a970f..9a096f24f 100644
--- a/compiler/rustc_typeck/src/check/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -1,9 +1,10 @@
-use crate::check::{FnCtxt, LocalTy, UserType};
+use crate::{FnCtxt, LocalTy};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::Ty;
+use rustc_middle::ty::UserType;
use rustc_span::Span;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 016f4056b..122ad7009 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -210,7 +210,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
}
/// For an expression with an uninhabited return type (e.g. a function that returns !),
- /// this adds a self edge to to the CFG to model the fact that the function does not
+ /// this adds a self edge to the CFG to model the fact that the function does not
/// return.
fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.typeck_results.expr_ty(expr);
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e..139d17d2e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
index c0a0bfe8e..c0a0bfe8e 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index 518cd7342..4f3bdfbe7 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -14,7 +14,7 @@
use self::cfg_build::build_control_flow_graph;
use self::record_consumed_borrow::find_consumed_and_borrowed;
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use hir::def_id::DefId;
use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index e22675e9d..bfe95852a 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -1,13 +1,16 @@
use super::TrackedValue;
use crate::{
- check::FnCtxt,
expr_use_visitor::{self, ExprUseVisitor},
+ FnCtxt,
};
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::{
+ hir::place::{PlaceBase, Projection, ProjectionKind},
+ ty::TypeVisitable,
+};
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
@@ -198,7 +201,13 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
// If the type being assigned needs dropped, then the mutation counts as a borrow
// since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
- if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
+ let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
+ if ty.needs_infer() {
+ self.tcx.sess.delay_span_bug(
+ self.tcx.hir().span(assignee_place.hir_id),
+ &format!("inference variables in {ty}"),
+ );
+ } else if ty.needs_drop(self.tcx, self.param_env) {
self.places
.borrowed
.insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index 7ab6d9e2b..b7dd599cd 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -6,7 +6,7 @@
use self::drop_ranges::DropRanges;
use super::FnCtxt;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::pluralize;
+use rustc_errors::{pluralize, DelayDm};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -218,7 +218,8 @@ pub fn resolve_interior<'a, 'tcx>(
.filter_map(|mut cause| {
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
// can.
- let erased = fcx.tcx.erase_regions(cause.ty);
+ let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
+ let erased = fcx.tcx.erase_regions(ty);
if captured_tys.insert(erased) {
// Replace all regions inside the generator interior with late bound regions.
// Note that each region slot in the types gets a new fresh late bound region,
@@ -263,7 +264,7 @@ pub fn resolve_interior<'a, 'tcx>(
// Unify the type variable inside the generator with the new witness
match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(interior, witness) {
Ok(ok) => fcx.register_infer_ok_obligations(ok),
- _ => bug!(),
+ _ => bug!("failed to relate {interior} and {witness}"),
}
}
@@ -376,15 +377,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
debug!("is_borrowed_temporary: {:?}", self.drop_ranges.is_borrowed_temporary(expr));
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr);
- let may_need_drop = |ty: Ty<'tcx>| {
- // Avoid ICEs in needs_drop.
- let ty = self.fcx.resolve_vars_if_possible(ty);
- let ty = self.fcx.tcx.erase_regions(ty);
- if ty.needs_infer() {
- return true;
- }
- ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
- };
// Typically, the value produced by an expression is consumed by its parent in some way,
// so we only have to check if the parent contains a yield (note that the parent may, for
@@ -402,9 +394,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
// src/test/ui/generator/drop-tracking-parent-expression.rs.
let scope = if self.drop_ranges.is_borrowed_temporary(expr)
|| ty.map_or(true, |ty| {
- let needs_drop = may_need_drop(ty);
- debug!(?needs_drop, ?ty);
- needs_drop
+ // Avoid ICEs in needs_drop.
+ let ty = self.fcx.resolve_vars_if_possible(ty);
+ let ty = self.fcx.tcx.erase_regions(ty);
+ if ty.needs_infer() {
+ self.fcx
+ .tcx
+ .sess
+ .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+ true
+ } else {
+ ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
+ }
}) {
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
} else {
@@ -609,33 +610,33 @@ fn check_must_not_suspend_def(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
- |lint| {
- let msg = format!(
+ DelayDm(|| {
+ format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
- );
- let mut err = lint.build(&msg);
-
+ )
+ }),
+ |lint| {
// add span pointing to the offending yield/await
- err.span_label(data.yield_span, "the value is held across this suspend point");
+ lint.span_label(data.yield_span, "the value is held across this suspend point");
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
- err.span_note(data.source_span, note.as_str());
+ lint.span_note(data.source_span, note.as_str());
}
// Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well?
- err.span_help(
+ lint.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
- err.emit();
+ lint
},
);
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 37c830d4e..0fb7651b3 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
use rustc_infer::infer;
-use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -29,10 +29,10 @@ use std::ops::Deref;
/// Here, the function `foo()` and the closure passed to
/// `bar()` will each have their own `FnCtxt`, but they will
/// share the inherited fields.
-pub struct Inherited<'a, 'tcx> {
- pub(super) infcx: InferCtxt<'a, 'tcx>,
+pub struct Inherited<'tcx> {
+ pub(super) infcx: InferCtxt<'tcx>,
- pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
+ pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
@@ -55,7 +55,7 @@ pub struct Inherited<'a, 'tcx> {
pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
- pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>,
+ pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, hir::HirId)>>,
pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
@@ -70,22 +70,23 @@ pub struct Inherited<'a, 'tcx> {
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
}
-impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
- type Target = InferCtxt<'a, 'tcx>;
+impl<'tcx> Deref for Inherited<'tcx> {
+ type Target = InferCtxt<'tcx>;
fn deref(&self) -> &Self::Target {
&self.infcx
}
}
/// A temporary returned by `Inherited::build(...)`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
+/// for multiple `InferCtxt` to share the same `typeck_results`
/// without using `Rc` or something similar.
pub struct InheritedBuilder<'tcx> {
infcx: infer::InferCtxtBuilder<'tcx>,
def_id: LocalDefId,
+ typeck_results: RefCell<ty::TypeckResults<'tcx>>,
}
-impl<'tcx> Inherited<'_, 'tcx> {
+impl<'tcx> Inherited<'tcx> {
pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> {
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
@@ -93,7 +94,7 @@ impl<'tcx> Inherited<'_, 'tcx> {
infcx: tcx
.infer_ctxt()
.ignoring_regions()
- .with_fresh_in_progress_typeck_results(hir_owner)
+ .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
.with_normalize_fn_sig_for_diagnostic(Lrc::new(move |infcx, fn_sig| {
if fn_sig.has_escaping_bound_vars() {
return fn_sig;
@@ -117,26 +118,29 @@ impl<'tcx> Inherited<'_, 'tcx> {
})
})),
def_id,
+ typeck_results: RefCell::new(ty::TypeckResults::new(hir_owner)),
}
}
}
impl<'tcx> InheritedBuilder<'tcx> {
- pub fn enter<F, R>(&mut self, f: F) -> R
+ pub fn enter<F, R>(mut self, f: F) -> R
where
- F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R,
+ F: FnOnce(&Inherited<'tcx>) -> R,
{
let def_id = self.def_id;
- self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
+ f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results))
}
}
-impl<'a, 'tcx> Inherited<'a, 'tcx> {
- fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
+impl<'tcx> Inherited<'tcx> {
+ fn new(
+ infcx: InferCtxt<'tcx>,
+ def_id: LocalDefId,
+ typeck_results: RefCell<ty::TypeckResults<'tcx>>,
+ ) -> Self {
let tcx = infcx.tcx;
let body_id = tcx.hir().maybe_body_owned_by(def_id);
- let typeck_results =
- infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
Inherited {
typeck_results,
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
new file mode 100644
index 000000000..9812d96fc
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -0,0 +1,108 @@
+use hir::HirId;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_index::vec::Idx;
+use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::{Pointer, VariantIdx};
+
+use super::FnCtxt;
+
+/// If the type is `Option<T>`, it will return `T`, otherwise
+/// the type itself. Works on most `Option`-like types.
+fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+ let ty::Adt(def, substs) = *ty.kind() else { return ty };
+
+ if def.variants().len() == 2 && !def.repr().c() && def.repr().int.is_none() {
+ let data_idx;
+
+ let one = VariantIdx::new(1);
+ let zero = VariantIdx::new(0);
+
+ if def.variant(zero).fields.is_empty() {
+ data_idx = one;
+ } else if def.variant(one).fields.is_empty() {
+ data_idx = zero;
+ } else {
+ return ty;
+ }
+
+ if def.variant(data_idx).fields.len() == 1 {
+ return def.variant(data_idx).fields[0].ty(tcx, substs);
+ }
+ }
+
+ ty
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
+ let tcx = self.tcx;
+ let span = tcx.hir().span(hir_id);
+ let normalize = |ty| {
+ let ty = self.resolve_vars_if_possible(ty);
+ self.tcx.normalize_erasing_regions(self.param_env, ty)
+ };
+ let from = normalize(from);
+ let to = normalize(to);
+ trace!(?from, ?to);
+
+ // Transmutes that are only changing lifetimes are always ok.
+ if from == to {
+ return;
+ }
+
+ let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env);
+ let sk_from = skel(from);
+ let sk_to = skel(to);
+ trace!(?sk_from, ?sk_to);
+
+ // Check for same size using the skeletons.
+ if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
+ if sk_from.same_size(sk_to) {
+ return;
+ }
+
+ // Special-case transmuting from `typeof(function)` and
+ // `Option<typeof(function)>` to present a clearer error.
+ let from = unpack_option_like(tcx, from);
+ if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+ struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
+ .note(&format!("source type: {from}"))
+ .note(&format!("target type: {to}"))
+ .help("cast with `as` to a pointer instead")
+ .emit();
+ return;
+ }
+ }
+
+ // Try to display a sensible error with as much information as possible.
+ let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
+ Ok(SizeSkeleton::Known(size)) => format!("{} bits", size.bits()),
+ Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
+ Err(LayoutError::Unknown(bad)) => {
+ if bad == ty {
+ "this type does not have a fixed size".to_owned()
+ } else {
+ format!("size can vary because of {bad}")
+ }
+ }
+ Err(err) => err.to_string(),
+ };
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0512,
+ "cannot transmute between types of different sizes, \
+ or dependently-sized types"
+ );
+ if from == to {
+ err.note(&format!("`{from}` does not have a fixed size"));
+ } else {
+ err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+ .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+ }
+ err.emit();
+ }
+}
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
new file mode 100644
index 000000000..959c54866
--- /dev/null
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -0,0 +1,507 @@
+#![feature(if_let_guard)]
+#![feature(let_chains)]
+#![feature(try_blocks)]
+#![feature(never_type)]
+#![feature(min_specialization)]
+#![feature(control_flow_enum)]
+#![feature(drain_filter)]
+#![allow(rustc::potential_query_instability)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate tracing;
+
+#[macro_use]
+extern crate rustc_middle;
+
+mod _match;
+mod autoderef;
+mod callee;
+// Used by clippy;
+pub mod cast;
+mod check;
+mod closure;
+mod coercion;
+mod demand;
+mod diverges;
+mod errors;
+mod expectation;
+mod expr;
+// Used by clippy;
+pub mod expr_use_visitor;
+mod fallback;
+mod fn_ctxt;
+mod gather_locals;
+mod generator_interior;
+mod inherited;
+mod intrinsicck;
+mod mem_categorization;
+mod method;
+mod op;
+mod pat;
+mod place_op;
+mod rvalue_scopes;
+mod upvar;
+mod writeback;
+
+pub use diverges::Diverges;
+pub use expectation::Expectation;
+pub use fn_ctxt::*;
+pub use inherited::{Inherited, InheritedBuilder};
+
+use crate::check::check_fn;
+use crate::coercion::DynamicCoerceMany;
+use crate::gather_locals::GatherLocalsVisitor;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{HirIdMap, Node};
+use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::check::check_abi;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_middle::traits;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config;
+use rustc_session::Session;
+use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::Span;
+
+#[macro_export]
+macro_rules! type_error_struct {
+ ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+ let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
+
+ if $typ.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ err
+ })
+}
+
+/// The type of a local binding, including the revealed type for anon types.
+#[derive(Copy, Clone, Debug)]
+pub struct LocalTy<'tcx> {
+ decl_ty: Ty<'tcx>,
+ revealed_ty: Ty<'tcx>,
+}
+
+#[derive(Copy, Clone)]
+pub struct UnsafetyState {
+ pub def: hir::HirId,
+ pub unsafety: hir::Unsafety,
+ from_fn: bool,
+}
+
+impl UnsafetyState {
+ pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState {
+ UnsafetyState { def, unsafety, from_fn: true }
+ }
+
+ pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
+ use hir::BlockCheckMode;
+ match self.unsafety {
+ // If this unsafe, then if the outer function was already marked as
+ // unsafe we shouldn't attribute the unsafe'ness to the block. This
+ // way the block can be warned about instead of ignoring this
+ // extraneous block (functions are never warned about).
+ hir::Unsafety::Unsafe if self.from_fn => self,
+
+ unsafety => {
+ let (unsafety, def) = match blk.rules {
+ BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id),
+ BlockCheckMode::DefaultBlock => (unsafety, self.def),
+ };
+ UnsafetyState { def, unsafety, from_fn: false }
+ }
+ }
+ }
+}
+
+/// If this `DefId` is a "primary tables entry", returns
+/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
+///
+/// If this function returns `Some`, then `typeck_results(def_id)` will
+/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
+/// may not succeed. In some cases where this function returns `None`
+/// (notably closures), `typeck_results(def_id)` would wind up
+/// redirecting to the owning function.
+fn primary_body_of(
+ tcx: TyCtxt<'_>,
+ id: hir::HirId,
+) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
+ match tcx.hir().get(id) {
+ Node::Item(item) => match item.kind {
+ hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
+ Some((body, Some(ty), None))
+ }
+ hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
+ _ => None,
+ },
+ Node::TraitItem(item) => match item.kind {
+ hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)),
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+ Some((body, None, Some(sig)))
+ }
+ _ => None,
+ },
+ Node::ImplItem(item) => match item.kind {
+ hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)),
+ hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))),
+ _ => None,
+ },
+ Node::AnonConst(constant) => Some((constant.body, None, None)),
+ _ => None,
+ }
+}
+
+fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ // Closures' typeck results come from their outermost function,
+ // as they are part of the same "inference environment".
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
+ }
+
+ if let Some(def_id) = def_id.as_local() {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
+ primary_body_of(tcx, id).is_some()
+ } else {
+ false
+ }
+}
+
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
+ &*tcx.typeck(def_id).used_trait_imports
+}
+
+fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
+ tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
+}
+
+fn typeck_const_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (did, param_did): (LocalDefId, DefId),
+) -> &ty::TypeckResults<'tcx> {
+ let fallback = move || tcx.type_of(param_did);
+ typeck_with_fallback(tcx, did, fallback)
+}
+
+fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+ if let Some(param_did) = tcx.opt_const_param_of(def_id) {
+ tcx.typeck_const_arg((def_id, param_did))
+ } else {
+ let fallback = move || tcx.type_of(def_id.to_def_id());
+ typeck_with_fallback(tcx, def_id, fallback)
+ }
+}
+
+/// Used only to get `TypeckResults` for type inference during error recovery.
+/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
+fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
+ let fallback = move || {
+ let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
+ tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+ };
+ typeck_with_fallback(tcx, def_id, fallback)
+}
+
+fn typeck_with_fallback<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+ fallback: impl Fn() -> Ty<'tcx> + 'tcx,
+) -> &'tcx ty::TypeckResults<'tcx> {
+ // Closures' typeck results come from their outermost function,
+ // as they are part of the same "inference environment".
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
+ }
+
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let span = tcx.hir().span(id);
+
+ // Figure out what primary body this item has.
+ let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
+ span_bug!(span, "can't type-check body of {:?}", def_id);
+ });
+ let body = tcx.hir().body(body_id);
+
+ let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
+ let param_env = tcx.param_env(def_id);
+ let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+ let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+ let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+ <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
+ } else {
+ tcx.fn_sig(def_id)
+ };
+
+ check_abi(tcx, id, span, fn_sig.abi());
+
+ // Compute the function signature from point of view of inside the fn.
+ let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+ let fn_sig = inh.normalize_associated_types_in(
+ body.value.span,
+ body_id.hir_id,
+ param_env,
+ fn_sig,
+ );
+ check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+ } else {
+ let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
+ let expected_type = body_ty
+ .and_then(|ty| match ty.kind {
+ hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
+ _ => None,
+ })
+ .unwrap_or_else(|| match tcx.hir().get(id) {
+ Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::ConstBlock(ref anon_const),
+ ..
+ }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ }),
+ Node::Ty(&hir::Ty {
+ kind: hir::TyKind::Typeof(ref anon_const), ..
+ }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span,
+ }),
+ Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
+ | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
+ let operand_ty = asm
+ .operands
+ .iter()
+ .filter_map(|(op, _op_sp)| match op {
+ hir::InlineAsmOperand::Const { anon_const }
+ if anon_const.hir_id == id =>
+ {
+ // Inline assembly constants must be integers.
+ Some(fcx.next_int_var())
+ }
+ hir::InlineAsmOperand::SymFn { anon_const }
+ if anon_const.hir_id == id =>
+ {
+ Some(fcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span,
+ }))
+ }
+ _ => None,
+ })
+ .next();
+ operand_ty.unwrap_or_else(fallback)
+ }
+ _ => fallback(),
+ },
+ _ => fallback(),
+ });
+
+ let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type);
+ fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+ // Gather locals in statics (because of block expressions).
+ GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ fcx.check_expr_coercable_to_type(&body.value, expected_type, None);
+
+ fcx.write_ty(id, expected_type);
+
+ fcx
+ };
+
+ let fallback_has_occurred = fcx.type_inference_fallback();
+
+ // Even though coercion casts provide type hints, we check casts after fallback for
+ // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+ fcx.check_casts();
+ fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+ // Closure and generator analysis may run after fallback
+ // because they don't constrain other type variables.
+ // Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
+ let prev_constness = fcx.param_env.constness();
+ fcx.param_env = fcx.param_env.without_const();
+ fcx.closure_analyze(body);
+ fcx.param_env = fcx.param_env.with_constness(prev_constness);
+ assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+ // Before the generator analysis, temporary scopes shall be marked to provide more
+ // precise information on types to be captured.
+ fcx.resolve_rvalue_scopes(def_id.to_def_id());
+ fcx.resolve_generator_interiors(def_id.to_def_id());
+
+ for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
+ let ty = fcx.normalize_ty(span, ty);
+ fcx.require_type_is_sized(ty, span, code);
+ }
+
+ fcx.select_all_obligations_or_error();
+
+ if !fcx.infcx.is_tainted_by_errors() {
+ fcx.check_transmutes();
+ }
+
+ fcx.check_asms();
+
+ fcx.infcx.skip_region_resolution();
+
+ fcx.resolve_type_vars_in_body(body)
+ });
+
+ // Consistency check our TypeckResults instance can hold all ItemLocalIds
+ // it will need to hold.
+ assert_eq!(typeck_results.hir_owner, id.owner);
+
+ typeck_results
+}
+
+/// When `check_fn` is invoked on a generator (i.e., a body that
+/// includes yield), it returns back some information about the yield
+/// points.
+struct GeneratorTypes<'tcx> {
+ /// Type of generator argument / values returned by `yield`.
+ resume_ty: Ty<'tcx>,
+
+ /// Type of value that is yielded.
+ yield_ty: Ty<'tcx>,
+
+ /// Types that are captured (see `GeneratorInterior` for more).
+ interior: Ty<'tcx>,
+
+ /// Indicates if the generator is movable or static (immovable).
+ movability: hir::Movability,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Needs {
+ MutPlace,
+ None,
+}
+
+impl Needs {
+ fn maybe_mut_place(m: hir::Mutability) -> Self {
+ match m {
+ hir::Mutability::Mut => Needs::MutPlace,
+ hir::Mutability::Not => Needs::None,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum PlaceOp {
+ Deref,
+ Index,
+}
+
+pub struct BreakableCtxt<'tcx> {
+ may_break: bool,
+
+ // this is `null` for loops where break with a value is illegal,
+ // such as `while`, `for`, and `while let`
+ coerce: Option<DynamicCoerceMany<'tcx>>,
+}
+
+pub struct EnclosingBreakables<'tcx> {
+ stack: Vec<BreakableCtxt<'tcx>>,
+ by_id: HirIdMap<usize>,
+}
+
+impl<'tcx> EnclosingBreakables<'tcx> {
+ fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
+ self.opt_find_breakable(target_id).unwrap_or_else(|| {
+ bug!("could not find enclosing breakable with id {}", target_id);
+ })
+ }
+
+ fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
+ match self.by_id.get(&target_id) {
+ Some(ix) => Some(&mut self.stack[*ix]),
+ None => None,
+ }
+ }
+}
+
+fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0533,
+ "expected unit struct, unit variant or constant, found {} `{}`",
+ res.descr(),
+ rustc_hir_pretty::qpath_to_string(qpath),
+ )
+ .emit();
+}
+
+/// Controls whether the arguments are tupled. This is used for the call
+/// operator.
+///
+/// Tupling means that all call-side arguments are packed into a tuple and
+/// passed as a single parameter. For example, if tupling is enabled, this
+/// function:
+/// ```
+/// fn f(x: (isize, isize)) {}
+/// ```
+/// Can be called as:
+/// ```ignore UNSOLVED (can this be done in user code?)
+/// # fn f(x: (isize, isize)) {}
+/// f(1, 2);
+/// ```
+/// Instead of:
+/// ```
+/// # fn f(x: (isize, isize)) {}
+/// f((1, 2));
+/// ```
+#[derive(Clone, Eq, PartialEq)]
+enum TupleArgumentsFlag {
+ DontTupleArguments,
+ TupleArguments,
+}
+
+fn fatally_break_rust(sess: &Session) {
+ let handler = sess.diagnostic();
+ handler.span_bug_no_panic(
+ MultiSpan::new(),
+ "It looks like you're trying to break rust; would you like some ICE?",
+ );
+ handler.note_without_error("the compiler expectedly panicked. this is a feature.");
+ handler.note_without_error(
+ "we would appreciate a joke overview: \
+ https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
+ );
+ handler.note_without_error(&format!(
+ "rustc {} running on {}",
+ option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ config::host_triple(),
+ ));
+}
+
+fn has_expected_num_generic_args<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_did: Option<DefId>,
+ expected: usize,
+) -> bool {
+ trait_did.map_or(true, |trait_did| {
+ let generics = tcx.generics_of(trait_did);
+ generics.count() == expected + if generics.has_self { 1 } else { 0 }
+ })
+}
+
+pub fn provide(providers: &mut Providers) {
+ method::provide(providers);
+ *providers = Providers {
+ typeck_item_bodies,
+ typeck_const_arg,
+ typeck,
+ diagnostic_only_typeck,
+ has_typeck_results,
+ used_trait_imports,
+ ..*providers
+ };
+}
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index ced919f66..362f1c343 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -92,7 +92,7 @@ impl HirNode for hir::Pat<'_> {
#[derive(Clone)]
pub(crate) struct MemCategorizationContext<'a, 'tcx> {
pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: LocalDefId,
upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
@@ -103,7 +103,7 @@ pub(crate) type McResult<T> = Result<T, ()>;
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// Creates a `MemCategorizationContext`.
pub(crate) fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: LocalDefId,
typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -184,7 +184,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// modes #42640) may look like `Some(x)` but in fact have
/// implicit deref patterns attached (e.g., it is really
/// `&Some(x)`). In that case, we return the "outermost" type
- /// (e.g., `&Option<T>).
+ /// (e.g., `&Option<T>`).
pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
// Check for implicit `&` types wrapping the pattern; note
// that these are never attached to binding patterns, so
@@ -265,6 +265,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
}
+ #[instrument(level = "debug", skip(self, previous))]
fn cat_expr_adjusted_with<F>(
&self,
expr: &hir::Expr<'_>,
@@ -274,7 +275,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
where
F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
{
- debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr);
let target = self.resolve_vars_if_possible(adjustment.target);
match adjustment.kind {
adjustment::Adjust::Deref(overloaded) => {
@@ -292,13 +292,15 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
adjustment::Adjust::NeverToAny
| adjustment::Adjust::Pointer(_)
- | adjustment::Adjust::Borrow(_) => {
+ | adjustment::Adjust::Borrow(_)
+ | adjustment::Adjust::DynStar => {
// Result is an rvalue.
Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
}
}
}
+ #[instrument(level = "debug", skip(self))]
pub(crate) fn cat_expr_unadjusted(
&self,
expr: &hir::Expr<'_>,
@@ -387,6 +389,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}
+ #[instrument(level = "debug", skip(self, span))]
pub(crate) fn cat_res(
&self,
hir_id: hir::HirId,
@@ -394,8 +397,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
expr_ty: Ty<'tcx>,
res: Res,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res);
-
match res {
Res::Def(
DefKind::Ctor(..)
@@ -475,13 +476,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ret
}
+ #[instrument(level = "debug", skip(self))]
fn cat_overloaded_place(
&self,
expr: &hir::Expr<'_>,
base: &hir::Expr<'_>,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base);
-
// Reconstruct the output assuming it's a reference with the
// same region and mutability as the receiver. This holds for
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
@@ -497,13 +497,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
self.cat_deref(expr, base)
}
+ #[instrument(level = "debug", skip(self, node))]
fn cat_deref(
&self,
node: &impl HirNode,
base_place: PlaceWithHirId<'tcx>,
) -> McResult<PlaceWithHirId<'tcx>> {
- debug!("cat_deref: base_place={:?}", base_place);
-
let base_curr_ty = base_place.place.ty();
let deref_ty = match base_curr_ty.builtin_deref(true) {
Some(mt) => mt.ty,
@@ -562,7 +561,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
| Res::SelfCtor(..)
- | Res::SelfTy { .. } => {
+ | Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. } => {
// Structs and Unions have only have one variant.
Ok(VariantIdx::new(0))
}
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 59fd5c315..be4ea9986 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -1,16 +1,16 @@
use super::{probe, MethodCallee};
-use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
-use crate::check::{callee, FnCtxt};
+use crate::{callee, FnCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
+use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use rustc_infer::infer::{self, InferOk};
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{self, Subst, SubstsRef};
+use rustc_middle::ty::subst::{self, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 249e9c66b..a1278edef 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -10,15 +10,14 @@ mod suggest;
pub use self::suggest::SelfSource;
pub use self::MethodError::*;
-use crate::check::{Expectation, FnCtxt};
-use crate::ObligationCause;
+use crate::{Expectation, FnCtxt};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
use rustc_span::symbol::Ident;
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 392695cca..3c98a2aa3 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -1,3 +1,7 @@
+use crate::{
+ method::probe::{self, Pick},
+ FnCtxt,
+};
use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
@@ -12,11 +16,6 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use crate::check::{
- method::probe::{self, Pick},
- FnCtxt,
-};
-
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(super) fn lint_dot_call_from_2018(
&self,
@@ -82,14 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
self_expr.hir_id,
self_expr.span,
+ format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = self_expr.span;
- let mut lint = lint.build(&format!(
- "trait method `{}` will become ambiguous in Rust 2021",
- segment.ident.name
- ));
-
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
@@ -133,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- lint.emit();
+ lint
},
);
} else {
@@ -143,6 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prelude_or_array_lint,
call_expr.hir_id,
call_expr.span,
+ format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|lint| {
let sp = call_expr.span;
let trait_name = self.trait_path_or_bare_name(
@@ -151,11 +147,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pick.item.container_id(self.tcx),
);
- let mut lint = lint.build(&format!(
- "trait method `{}` will become ambiguous in Rust 2021",
- segment.ident.name
- ));
-
let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
let args = args
@@ -202,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- lint.emit();
+ lint
},
);
}
@@ -257,15 +248,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}
- self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
- // "type" refers to either a type or, more likely, a trait from which
- // the associated function or method is from.
- let container_id = pick.item.container_id(self.tcx);
- let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
- let trait_generics = self.tcx.generics_of(container_id);
-
- let trait_name =
- if trait_generics.params.len() <= trait_generics.has_self as usize {
+ self.tcx.struct_span_lint_hir(
+ RUST_2021_PRELUDE_COLLISIONS,
+ expr_id,
+ span,
+ format!(
+ "trait-associated function `{}` will become ambiguous in Rust 2021",
+ method_name.name
+ ),
+ |lint| {
+ // "type" refers to either a type or, more likely, a trait from which
+ // the associated function or method is from.
+ let container_id = pick.item.container_id(self.tcx);
+ let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+ let trait_generics = self.tcx.generics_of(container_id);
+
+ let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
+ {
trait_path
} else {
let counts = trait_generics.own_counts();
@@ -282,44 +281,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
- let mut lint = lint.build(&format!(
- "trait-associated function `{}` will become ambiguous in Rust 2021",
- method_name.name
- ));
-
- let mut self_ty_name = self_ty_span
- .find_ancestor_inside(span)
- .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
- .unwrap_or_else(|| self_ty.to_string());
-
- // Get the number of generics the self type has (if an Adt) unless we can determine that
- // the user has written the self type with generics already which we (naively) do by looking
- // for a "<" in `self_ty_name`.
- if !self_ty_name.contains('<') {
- if let Adt(def, _) = self_ty.kind() {
- let generics = self.tcx.generics_of(def.did());
- if !generics.params.is_empty() {
- let counts = generics.own_counts();
- self_ty_name += &format!(
- "<{}>",
- std::iter::repeat("'_")
- .take(counts.lifetimes)
- .chain(std::iter::repeat("_").take(counts.types + counts.consts))
- .collect::<Vec<_>>()
- .join(", ")
- );
+ let mut self_ty_name = self_ty_span
+ .find_ancestor_inside(span)
+ .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+ .unwrap_or_else(|| self_ty.to_string());
+
+ // Get the number of generics the self type has (if an Adt) unless we can determine that
+ // the user has written the self type with generics already which we (naively) do by looking
+ // for a "<" in `self_ty_name`.
+ if !self_ty_name.contains('<') {
+ if let Adt(def, _) = self_ty.kind() {
+ let generics = self.tcx.generics_of(def.did());
+ if !generics.params.is_empty() {
+ let counts = generics.own_counts();
+ self_ty_name += &format!(
+ "<{}>",
+ std::iter::repeat("'_")
+ .take(counts.lifetimes)
+ .chain(
+ std::iter::repeat("_").take(counts.types + counts.consts)
+ )
+ .collect::<Vec<_>>()
+ .join(", ")
+ );
+ }
}
}
- }
- lint.span_suggestion(
- span,
- "disambiguate the associated function",
- format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
- Applicability::MachineApplicable,
- );
-
- lint.emit();
- });
+ lint.span_suggestion(
+ span,
+ "disambiguate the associated function",
+ format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
+ Applicability::MachineApplicable,
+ );
+
+ lint
+ },
+ );
}
fn trait_path_or_bare_name(
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index e9f55ab34..28aa2302f 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,14 +3,12 @@ use super::CandidateSource;
use super::MethodError;
use super::NoMatchData;
-use crate::check::FnCtxt;
use crate::errors::MethodCallOnUnknownType;
-use crate::hir::def::DefKind;
-use crate::hir::def_id::DefId;
-
+use crate::FnCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def::Namespace;
use rustc_infer::infer::canonical::OriginalQueryValues;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
@@ -19,10 +17,11 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::lint;
+use rustc_span::def_id::DefId;
use rustc_span::def_id::LocalDefId;
use rustc_span::lev_distance::{
find_best_match_for_name_with_substrings, lev_distance_with_substrings,
@@ -253,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// would result in an error (basically, the same criteria we
/// would use to decide if a method is a plausible fit for
/// ambiguity purposes).
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self, candidate_filter))]
pub fn probe_for_return_type(
&self,
span: Span,
@@ -261,6 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return_type: Ty<'tcx>,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
) -> Vec<ty::AssocItem> {
let method_names = self
.probe_op(
@@ -272,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self_ty,
scope_expr_id,
ProbeScope::AllTraits,
- |probe_cx| Ok(probe_cx.candidate_method_names()),
+ |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)),
)
.unwrap_or_default();
method_names
@@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id,
span,
- |lint| {
- lint.build("type annotations needed").emit();
- },
+ "type annotations needed",
+ |lint| lint,
);
}
} else {
@@ -473,69 +472,65 @@ fn method_autoderef_steps<'tcx>(
) -> MethodAutoderefStepsResult<'tcx> {
debug!("method_autoderef_steps({:?})", goal);
- tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
- let ParamEnvAnd { param_env, value: self_ty } = goal;
-
- let mut autoderef =
- Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
- .include_raw_pointers()
- .silence_errors();
- let mut reached_raw_pointer = false;
- let mut steps: Vec<_> = autoderef
- .by_ref()
- .map(|(ty, d)| {
- let step = CandidateStep {
- self_ty: infcx.make_query_response_ignoring_pending_obligations(
- inference_vars.clone(),
- ty,
- ),
- autoderefs: d,
- from_unsafe_deref: reached_raw_pointer,
- unsize: false,
- };
- if let ty::RawPtr(_) = ty.kind() {
- // all the subsequent steps will be from_unsafe_deref
- reached_raw_pointer = true;
- }
- step
- })
- .collect();
-
- let final_ty = autoderef.final_ty(true);
- let opt_bad_ty = match final_ty.kind() {
- ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
- reached_raw_pointer,
- ty: infcx
- .make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
- }),
- ty::Array(elem_ty, _) => {
- let dereferences = steps.len() - 1;
-
- steps.push(CandidateStep {
- self_ty: infcx.make_query_response_ignoring_pending_obligations(
- inference_vars,
- infcx.tcx.mk_slice(*elem_ty),
- ),
- autoderefs: dereferences,
- // this could be from an unsafe deref if we had
- // a *mut/const [T; N]
- from_unsafe_deref: reached_raw_pointer,
- unsize: true,
- });
-
- None
+ let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
+ let ParamEnvAnd { param_env, value: self_ty } = goal;
+
+ let mut autoderef =
+ Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+ .include_raw_pointers()
+ .silence_errors();
+ let mut reached_raw_pointer = false;
+ let mut steps: Vec<_> = autoderef
+ .by_ref()
+ .map(|(ty, d)| {
+ let step = CandidateStep {
+ self_ty: infcx
+ .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
+ autoderefs: d,
+ from_unsafe_deref: reached_raw_pointer,
+ unsize: false,
+ };
+ if let ty::RawPtr(_) = ty.kind() {
+ // all the subsequent steps will be from_unsafe_deref
+ reached_raw_pointer = true;
}
- _ => None,
- };
-
- debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+ step
+ })
+ .collect();
+
+ let final_ty = autoderef.final_ty(true);
+ let opt_bad_ty = match final_ty.kind() {
+ ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
+ reached_raw_pointer,
+ ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
+ }),
+ ty::Array(elem_ty, _) => {
+ let dereferences = steps.len() - 1;
+
+ steps.push(CandidateStep {
+ self_ty: infcx.make_query_response_ignoring_pending_obligations(
+ inference_vars,
+ infcx.tcx.mk_slice(*elem_ty),
+ ),
+ autoderefs: dereferences,
+ // this could be from an unsafe deref if we had
+ // a *mut/const [T; N]
+ from_unsafe_deref: reached_raw_pointer,
+ unsize: true,
+ });
- MethodAutoderefStepsResult {
- steps: tcx.arena.alloc_from_iter(steps),
- opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
- reached_recursion_limit: autoderef.reached_recursion_limit(),
+ None
}
- })
+ _ => None,
+ };
+
+ debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+
+ MethodAutoderefStepsResult {
+ steps: tcx.arena.alloc_from_iter(steps),
+ opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
+ reached_recursion_limit: autoderef.reached_recursion_limit(),
+ }
}
impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
@@ -972,12 +967,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- fn candidate_method_names(&self) -> Vec<Ident> {
+ fn candidate_method_names(
+ &self,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
+ ) -> Vec<Ident> {
let mut set = FxHashSet::default();
let mut names: Vec<_> = self
.inherent_candidates
.iter()
.chain(&self.extension_candidates)
+ .filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
self.matches_return_type(&candidate.item, None, return_ty)
@@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
stable_pick: &Pick<'_>,
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
) {
+ let def_kind = stable_pick.item.kind.as_def_kind();
self.tcx.struct_span_lint_hir(
lint::builtin::UNSTABLE_NAME_COLLISIONS,
self.scope_expr_id,
self.span,
+ format!(
+ "{} {} with this name may be added to the standard library in the future",
+ def_kind.article(),
+ def_kind.descr(stable_pick.item.def_id),
+ ),
|lint| {
- let def_kind = stable_pick.item.kind.as_def_kind();
- let mut diag = lint.build(&format!(
- "{} {} with this name may be added to the standard library in the future",
- def_kind.article(),
- def_kind.descr(stable_pick.item.def_id),
- ));
match (stable_pick.item.kind, stable_pick.item.container) {
(ty::AssocKind::Fn, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`.
- diag.help(&format!(
+ lint.help(&format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
self.tcx.def_path_str(stable_pick.item.def_id),
@@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
(ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
let def_id = stable_pick.item.container_id(self.tcx);
- diag.span_suggestion(
+ lint.span_suggestion(
self.span,
"use the fully qualified path to the associated const",
format!(
@@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates {
- diag.help(&format!(
+ lint.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
self.tcx.def_path_str(candidate.item.def_id),
@@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
- diag.emit();
+ lint
},
);
}
@@ -1695,7 +1694,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pcx.allow_similar_names = true;
pcx.assemble_inherent_candidates();
- let method_names = pcx.candidate_method_names();
+ let method_names = pcx.candidate_method_names(|_| true);
pcx.allow_similar_names = false;
let applicable_close_candidates: Vec<ty::AssocItem> = method_names
.iter()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 2d459b2cc..6c21ed902 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1,7 +1,9 @@
//! Give useful errors and suggestions to users when an item can't be
//! found or is otherwise invalid.
-use crate::check::FnCtxt;
+use crate::errors;
+use crate::FnCtxt;
+use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -21,7 +23,7 @@ use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
-use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
@@ -30,7 +32,7 @@ use rustc_trait_selection::traits::{
use std::cmp::Ordering;
use std::iter;
-use super::probe::{IsSuggestion, Mode, ProbeScope};
+use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -104,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let report_candidates = |span: Span,
err: &mut Diagnostic,
- mut sources: Vec<CandidateSource>,
+ sources: &mut Vec<CandidateSource>,
sugg_span: Span| {
sources.sort();
sources.dedup();
@@ -246,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match error {
MethodError::NoMatch(NoMatchData {
- static_candidates: static_sources,
+ static_candidates: mut static_sources,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
@@ -270,7 +272,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- if self.suggest_constraining_numerical_ty(
+ if self.suggest_wrapping_range_with_parens(
+ tcx, actual, source, span, item_name, &ty_str,
+ ) || self.suggest_constraining_numerical_ty(
tcx, actual, source, span, item_kind, item_name, &ty_str,
) {
return None;
@@ -418,9 +422,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
}
- report_candidates(span, &mut err, static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_sources, sugg_span);
} else if static_sources.len() > 1 {
- report_candidates(span, &mut err, static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_sources, sugg_span);
}
let mut bound_spans = vec![];
@@ -854,8 +858,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Avoid crashing.
return (None, None);
}
- let OnUnimplementedNote { message, label, .. } =
- self.on_unimplemented_note(trait_ref, &obligation);
+ let OnUnimplementedNote { message, label, .. } = self
+ .err_ctxt()
+ .on_unimplemented_note(trait_ref, &obligation);
(message, label)
})
.unwrap_or((None, None))
@@ -983,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_for_field_method(&mut err, source, span, actual, item_name);
}
- self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
+ self.check_for_inner_self(&mut err, source, span, actual, item_name);
bound_spans.sort();
bound_spans.dedup();
@@ -1002,6 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source,
out_of_scope_traits,
&unsatisfied_predicates,
+ &static_sources,
unsatisfied_bounds,
);
}
@@ -1074,7 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Some(err);
}
- MethodError::Ambiguity(sources) => {
+ MethodError::Ambiguity(mut sources) => {
let mut err = struct_span_err!(
self.sess(),
item_name.span,
@@ -1083,7 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, sources, sugg_span);
+ report_candidates(span, &mut err, &mut sources, sugg_span);
err.emit();
}
@@ -1200,6 +1206,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
+ /// Suggest possible range with adding parentheses, for example:
+ /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
+ fn suggest_wrapping_range_with_parens(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ actual: Ty<'tcx>,
+ source: SelfSource<'tcx>,
+ span: Span,
+ item_name: Ident,
+ ty_str: &str,
+ ) -> bool {
+ if let SelfSource::MethodCall(expr) = source {
+ for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+ if let Node::Expr(parent_expr) = parent {
+ let lang_item = match parent_expr.kind {
+ ExprKind::Struct(ref qpath, _, _) => match **qpath {
+ QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+ QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+ QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+ Some(LangItem::RangeToInclusive)
+ }
+ _ => None,
+ },
+ ExprKind::Call(ref func, _) => match func.kind {
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+ ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+ Some(LangItem::RangeInclusiveStruct)
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+
+ if lang_item.is_none() {
+ continue;
+ }
+
+ let span_included = match parent_expr.kind {
+ hir::ExprKind::Struct(_, eps, _) => {
+ eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+ }
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+ hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+ _ => false,
+ };
+
+ if !span_included {
+ continue;
+ }
+
+ let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+ let range_ty =
+ self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+
+ let pick = self.probe_for_name(
+ span,
+ Mode::MethodCall,
+ item_name,
+ IsSuggestion(true),
+ range_ty,
+ expr.hir_id,
+ ProbeScope::AllTraits,
+ );
+ if pick.is_ok() {
+ let range_span = parent_expr.span.with_hi(expr.span.hi());
+ tcx.sess.emit_err(errors::MissingParentheseInRange {
+ span,
+ ty_str: ty_str.to_string(),
+ method_name: item_name.as_str().to_string(),
+ add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+ func_name: item_name.name.as_str().to_string(),
+ left: range_span.shrink_to_lo(),
+ right: range_span.shrink_to_hi(),
+ }),
+ });
+ return true;
+ }
+ }
+ }
+ }
+ false
+ }
+
fn suggest_constraining_numerical_ty(
&self,
tcx: TyCtxt<'tcx>,
@@ -1262,7 +1351,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this is a floating point literal that ends with '.',
// get rid of it to stop this from becoming a member access.
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
-
err.span_suggestion(
lit.span,
&format!(
@@ -1395,7 +1483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_for_unwrap_self(
+ fn check_for_inner_self(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
@@ -1408,81 +1496,168 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
let ty::Adt(kind, substs) = actual.kind() else { return; };
- if !kind.is_enum() {
- return;
- }
+ match kind.adt_kind() {
+ ty::AdtKind::Enum => {
+ let matching_variants: Vec<_> = kind
+ .variants()
+ .iter()
+ .flat_map(|variant| {
+ let [field] = &variant.fields[..] else { return None; };
+ let field_ty = field.ty(tcx, substs);
+
+ // Skip `_`, since that'll just lead to ambiguity.
+ if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+ return None;
+ }
- let matching_variants: Vec<_> = kind
- .variants()
- .iter()
- .flat_map(|variant| {
- let [field] = &variant.fields[..] else { return None; };
- let field_ty = field.ty(tcx, substs);
+ self.lookup_probe(
+ span,
+ item_name,
+ field_ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ )
+ .ok()
+ .map(|pick| (variant, field, pick))
+ })
+ .collect();
+
+ let ret_ty_matches = |diagnostic_item| {
+ if let Some(ret_ty) = self
+ .ret_coercion
+ .as_ref()
+ .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+ && let ty::Adt(kind, _) = ret_ty.kind()
+ && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+ {
+ true
+ } else {
+ false
+ }
+ };
- // Skip `_`, since that'll just lead to ambiguity.
- if self.resolve_vars_if_possible(field_ty).is_ty_var() {
- return None;
+ match &matching_variants[..] {
+ [(_, field, pick)] => {
+ let self_ty = field.ty(tcx, substs);
+ err.span_note(
+ tcx.def_span(pick.item.def_id),
+ &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+ );
+ let (article, kind, variant, question) =
+ if tcx.is_diagnostic_item(sym::Result, kind.did()) {
+ ("a", "Result", "Err", ret_ty_matches(sym::Result))
+ } else if tcx.is_diagnostic_item(sym::Option, kind.did()) {
+ ("an", "Option", "None", ret_ty_matches(sym::Option))
+ } else {
+ return;
+ };
+ if question {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use the `?` operator to extract the `{self_ty}` value, propagating \
+ {article} `{kind}::{variant}` value to the caller"
+ ),
+ "?",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+ panicking if the value is {article} `{kind}::{variant}`"
+ ),
+ ".expect(\"REASON\")",
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
+ _ => {}
}
-
- self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
- .ok()
- .map(|pick| (variant, field, pick))
- })
- .collect();
-
- let ret_ty_matches = |diagnostic_item| {
- if let Some(ret_ty) = self
- .ret_coercion
- .as_ref()
- .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
- && let ty::Adt(kind, _) = ret_ty.kind()
- && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
- {
- true
- } else {
- false
}
- };
+ // Target wrapper types - types that wrap or pretend to wrap another type,
+ // perhaps this inner type is meant to be called?
+ ty::AdtKind::Struct | ty::AdtKind::Union => {
+ let [first] = ***substs else { return; };
+ let ty::GenericArgKind::Type(ty) = first.unpack() else { return; };
+ let Ok(pick) = self.lookup_probe(
+ span,
+ item_name,
+ ty,
+ call_expr,
+ ProbeScope::TraitsInScope,
+ ) else { return; };
- match &matching_variants[..] {
- [(_, field, pick)] => {
- let self_ty = field.ty(tcx, substs);
- err.span_note(
- tcx.def_span(pick.item.def_id),
- &format!("the method `{item_name}` exists on the type `{self_ty}`"),
- );
- let (article, kind, variant, question) =
- if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
- ("a", "Result", "Err", ret_ty_matches(sym::Result))
- } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
- ("an", "Option", "None", ret_ty_matches(sym::Option))
- } else {
- return;
+ let name = self.ty_to_value_string(actual);
+ let inner_id = kind.did();
+ let mutable = if let Some(AutorefOrPtrAdjustment::Autoref { mutbl, .. }) =
+ pick.autoref_or_ptr_adjustment
+ {
+ Some(mutbl)
+ } else {
+ None
+ };
+
+ if tcx.is_diagnostic_item(sym::LocalKey, inner_id) {
+ err.help("use `with` or `try_with` to access thread local storage");
+ } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() {
+ err.help(format!(
+ "if this `{name}` has been initialized, \
+ use one of the `assume_init` methods to access the inner value"
+ ));
+ } else if tcx.is_diagnostic_item(sym::RefCell, inner_id) {
+ let (suggestion, borrow_kind, panic_if) = match mutable {
+ Some(Mutability::Not) => (".borrow()", "borrow", "a mutable borrow exists"),
+ Some(Mutability::Mut) => {
+ (".borrow_mut()", "mutably borrow", "any borrows exist")
+ }
+ None => return,
};
- if question {
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
- "use the `?` operator to extract the `{self_ty}` value, propagating \
- {article} `{kind}::{variant}` value to the caller"
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+ panicking if {panic_if}"
),
- "?",
- Applicability::MachineApplicable,
+ suggestion,
+ Applicability::MaybeIncorrect,
);
- } else {
+ } else if tcx.is_diagnostic_item(sym::Mutex, inner_id) {
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
- "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
- panicking if the value is {article} `{kind}::{variant}`"
+ "use `.lock().unwrap()` to borrow the `{ty}`, \
+ blocking the current thread until it can be acquired"
),
- ".expect(\"REASON\")",
- Applicability::HasPlaceholders,
+ ".lock().unwrap()",
+ Applicability::MaybeIncorrect,
);
- }
+ } else if tcx.is_diagnostic_item(sym::RwLock, inner_id) {
+ let (suggestion, borrow_kind) = match mutable {
+ Some(Mutability::Not) => (".read().unwrap()", "borrow"),
+ Some(Mutability::Mut) => (".write().unwrap()", "mutably borrow"),
+ None => return,
+ };
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use `{suggestion}` to {borrow_kind} the `{ty}`, \
+ blocking the current thread until it can be acquired"
+ ),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ return;
+ };
+
+ err.span_note(
+ tcx.def_span(pick.item.def_id),
+ &format!("the method `{item_name}` exists on the type `{ty}`"),
+ );
}
- // FIXME(compiler-errors): Support suggestions for other matching enum variants
- _ => {}
}
}
@@ -1841,6 +2016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
+ static_candidates: &[CandidateSource],
unsatisfied_bounds: bool,
) {
let mut alt_rcvr_sugg = false;
@@ -1955,6 +2131,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => true,
})
.filter(|info| {
+ // Static candidates are already implemented, and known not to work
+ // Do not suggest them again
+ static_candidates.iter().all(|sc| match *sc {
+ CandidateSource::Trait(def_id) => def_id != info.def_id,
+ CandidateSource::Impl(def_id) => {
+ self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
+ }
+ })
+ })
+ .filter(|info| {
// We approximate the coherence rules to only suggest
// traits that are legal to implement by requiring that
// either the type or trait is local. Multi-dispatch means
@@ -2077,7 +2263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Colon,
Nothing,
}
- let ast_generics = hir.get_generics(id.owner).unwrap();
+ let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
let (sp, mut introducer) = if let Some(span) =
ast_generics.bounds_span_for_suggestions(def_id)
{
@@ -2236,6 +2422,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
+ /// FIXME: currently not working for suggesting `map_or_else`, see #102408
+ pub(crate) fn suggest_else_fn_with_closure(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ found: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ ) -> bool {
+ let Some((_def_id_or_name, output, _inputs)) = self.extract_callable_info(expr, found)
+ else { return false; };
+
+ if !self.can_coerce(output, expected) {
+ return false;
+ }
+
+ let parent = self.tcx.hir().get_parent_node(expr.hir_id);
+ if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) &&
+ let hir::ExprKind::MethodCall(
+ hir::PathSegment { ident: method_name, .. },
+ self_expr,
+ args,
+ ..,
+ ) = call_expr.kind &&
+ let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) {
+ let new_name = Ident {
+ name: Symbol::intern(&format!("{}_else", method_name.as_str())),
+ span: method_name.span,
+ };
+ let probe = self.lookup_probe(
+ expr.span,
+ new_name,
+ self_ty,
+ self_expr,
+ ProbeScope::TraitsInScope,
+ );
+
+ // check the method arguments number
+ if let Ok(pick) = probe &&
+ let fn_sig = self.tcx.fn_sig(pick.item.def_id) &&
+ let fn_args = fn_sig.skip_binder().inputs() &&
+ fn_args.len() == args.len() + 1 {
+ err.span_suggestion_verbose(
+ method_name.span.shrink_to_hi(),
+ &format!("try calling `{}` instead", new_name.name.as_str()),
+ "_else",
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+ false
+ }
+
/// Checks whether there is a local type somewhere in the chain of
/// autoderefs of `rcvr_ty`.
fn type_derefs_to_local(
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 4754717c2..895739976 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -2,7 +2,7 @@
use super::method::MethodCallee;
use super::{has_expected_num_generic_args, FnCtxt};
-use crate::check::Expectation;
+use crate::Expectation;
use rustc_ast as ast;
use rustc_errors::{self, struct_span_err, Applicability, Diagnostic};
use rustc_hir as hir;
@@ -13,11 +13,12 @@ use rustc_middle::ty::adjustment::{
};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
+use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
use rustc_type_ir::sty::TyKind::*;
@@ -470,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This has nothing here because it means we did string
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
- } else if lhs_ty.has_param_types_or_consts() {
+ } else if lhs_ty.has_non_region_param() {
// Look for a TraitPredicate in the Fulfillment errors,
// and use it to generate a suggestion.
//
@@ -511,7 +512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
- self.suggest_restricting_param_bound(
+ self.err_ctxt().suggest_restricting_param_bound(
&mut err,
trait_pred,
output_associated_item,
@@ -656,12 +657,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("cannot apply unary operator `{}`", op.as_str()),
);
- if operand_ty.has_param_types_or_consts() {
+ if operand_ty.has_non_region_param() {
let predicates = errors.iter().filter_map(|error| {
error.obligation.predicate.to_opt_poly_trait_pred()
});
for pred in predicates {
- self.suggest_restricting_param_bound(
+ self.err_ctxt().suggest_restricting_param_bound(
&mut err,
pred,
None,
@@ -677,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the previous expression was a block expression, suggest parentheses
// (turning this into a binary subtraction operation instead.)
// for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
- self.tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
+ err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
} else {
match actual.kind() {
Uint(_) if op == hir::UnOp::Neg => {
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 8906b622b..ea90da4a6 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,6 +1,5 @@
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use rustc_ast as ast;
-
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -1790,10 +1789,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
);
- self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
- let mut lint = build.build("some fields are not explicitly listed");
+ self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
-
lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
@@ -1801,7 +1798,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty,
));
- lint.emit();
+
+ lint
});
}
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2e0f37eba..ba8cf6926 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,5 +1,5 @@
-use crate::check::method::MethodCallee;
-use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
+use crate::method::MethodCallee;
+use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
diff --git a/compiler/rustc_typeck/src/check/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 22c9e7961..22c9e7961 100644
--- a/compiler/rustc_typeck/src/check/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 0b207a6c0..4dea40829 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -352,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// and that the path can be captured with required capture kind (depending on use in closure,
/// move closure etc.)
///
- /// Returns the set of of adjusted information along with the inferred closure kind and span
+ /// Returns the set of adjusted information along with the inferred closure kind and span
/// associated with the closure kind inference.
///
/// Note that we *always* infer a minimal kind, even if
@@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
closure_hir_id,
closure_head_span,
+ reasons.migration_message(),
|lint| {
- let mut diagnostics_builder = lint.build(
- &reasons.migration_message(),
- );
for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible
// for migration being needed
@@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
let cause_span = self.tcx.hir().span(*capture_expr_id);
- diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+ lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span } => {
- diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+ lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
self.tcx.hir().name(*var_hir_id),
));
}
@@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+ lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
}
UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+ lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
v = self.tcx.hir().name(*var_hir_id),
));
}
@@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match &lint_note.captures_info {
UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
let var_name = self.tcx.hir().name(*var_hir_id);
- diagnostics_builder.span_label(closure_head_span, format!("\
+ lint.span_label(closure_head_span, format!("\
in Rust 2018, this closure implements {missing_trait} \
as `{var_name}` implements {missing_trait}, but in Rust 2021, \
this closure will no longer implement {missing_trait} \
@@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
+ lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let diagnostic_msg = format!(
"add a dummy let to cause {} to be fully captured",
@@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We take the indentation from the next non-empty line.
let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
&diagnostic_msg,
format!("\n{indent}{migration_string};"),
@@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// braces, but with more than just the opening
// brace on the first line. We put the `let`
// directly after the `{`.
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
&diagnostic_msg,
format!(" {migration_string};"),
@@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// This is a closure without braces around the body.
// We add braces to add the `let` before the body.
- diagnostics_builder.multipart_suggestion(
+ lint.multipart_suggestion(
&diagnostic_msg,
vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
} else {
- diagnostics_builder.span_suggestion(
+ lint.span_suggestion(
closure_span,
&diagnostic_msg,
migration_string,
@@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- diagnostics_builder.emit();
+ lint
},
);
}
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 9ecf34e9a..1e26daa9c 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -2,7 +2,7 @@
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
-use crate::check::FnCtxt;
+use crate::FnCtxt;
use hir::def_id::LocalDefId;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
@@ -536,33 +536,37 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let opaque_types =
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
for (opaque_type_key, decl) in opaque_types {
- let hidden_type = match decl.origin {
- hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
- let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
- struct RecursionChecker {
- def_id: LocalDefId,
- }
- impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
- type BreakTy = ();
- fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::Opaque(def_id, _) = *t.kind() {
- if def_id == self.def_id.to_def_id() {
- return ControlFlow::Break(());
- }
- }
- t.super_visit_with(self)
+ let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
+ let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
+
+ struct RecursionChecker {
+ def_id: LocalDefId,
+ }
+ impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
+ type BreakTy = ();
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::Opaque(def_id, _) = *t.kind() {
+ if def_id == self.def_id.to_def_id() {
+ return ControlFlow::Break(());
}
}
- if ty
- .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
- .is_break()
- {
- return;
- }
- Some(ty)
+ t.super_visit_with(self)
}
- hir::OpaqueTyOrigin::TyAlias => None,
- };
+ }
+ if hidden_type
+ .visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
+ .is_break()
+ {
+ continue;
+ }
+
+ let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
+ opaque_type_key,
+ self.fcx.infcx.tcx,
+ true,
+ decl.origin,
+ );
+
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
}
}
@@ -700,7 +704,7 @@ impl Locatable for hir::HirId {
/// unresolved types and so forth.
struct Resolver<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
@@ -717,27 +721,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: false }
}
- fn report_type_error(&self, t: Ty<'tcx>) {
+ fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) {
if !self.tcx.sess.has_errors().is_some() {
self.infcx
+ .err_ctxt()
.emit_inference_failure_err(
Some(self.body.id()),
self.span.to_span(self.tcx),
- t.into(),
- E0282,
- false,
- )
- .emit();
- }
- }
-
- fn report_const_error(&self, c: ty::Const<'tcx>) {
- if self.tcx.sess.has_errors().is_none() {
- self.infcx
- .emit_inference_failure_err(
- Some(self.body.id()),
- self.span.to_span(self.tcx),
- c.into(),
+ p.into(),
E0282,
false,
)
@@ -782,7 +773,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
- self.report_type_error(t);
+ self.report_error(t);
self.replaced_with_error = true;
self.tcx().ty_error()
}
@@ -799,7 +790,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
Ok(ct) => self.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
- self.report_const_error(ct);
+ self.report_error(ct);
self.replaced_with_error = true;
self.tcx().const_error(ct.ty())
}