summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs63
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs99
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs265
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs121
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs332
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs65
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs153
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs126
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs212
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs273
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs198
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs228
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/variance/terms.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs15
28 files changed, 1609 insertions, 911 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index ba152cd48..21611e9c5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -427,7 +427,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let bound_vars = tcx.late_bound_vars(binding.hir_id);
ty::Binder::bind_with_vars(subst_output, bound_vars)
} else {
- // Include substitutions for generic parameters of associated types
+ // Append the generic arguments of the associated type to the `trait_ref`.
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index bd311c98f..ed4dde419 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -110,16 +110,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
// valid span, so we point at the whole path segment instead.
- let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span };
+ let is_dummy = assoc_name.span == DUMMY_SP;
+
let mut err = struct_span_err!(
self.tcx().sess,
- span,
+ if is_dummy { span } else { assoc_name.span },
E0220,
"associated type `{}` not found for `{}`",
assoc_name,
ty_param_name
);
+ if is_dummy {
+ err.span_label(span, format!("associated type `{assoc_name}` not found"));
+ return err.emit();
+ }
+
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
@@ -131,10 +137,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
- if let (Some(suggested_name), true) = (
- find_best_match_for_name(&all_candidate_names, assoc_name.name, None),
- assoc_name.span != DUMMY_SP,
- ) {
+ if let Some(suggested_name) =
+ find_best_match_for_name(&all_candidate_names, assoc_name.name, None)
+ {
err.span_suggestion(
assoc_name.span,
"there is an associated type with a similar name",
@@ -172,10 +177,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
})
.collect();
- if let (Some(suggested_name), true) = (
- find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
- assoc_name.span != DUMMY_SP,
- ) {
+ if let Some(suggested_name) =
+ find_best_match_for_name(&wider_candidate_names, assoc_name.name, None)
+ {
if let [best_trait] = visible_traits
.iter()
.filter(|trait_def_id| {
@@ -197,7 +201,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
- err.span_label(span, format!("associated type `{assoc_name}` not found"));
+ // If we still couldn't find any associated type, and only one associated type exists,
+ // suggests using it.
+
+ if all_candidate_names.len() == 1 {
+ // this should still compile, except on `#![feature(associated_type_defaults)]`
+ // where it could suggests `type A = Self::A`, thus recursing infinitely
+ let applicability = if self.tcx().features().associated_type_defaults {
+ Applicability::Unspecified
+ } else {
+ Applicability::MaybeIncorrect
+ };
+
+ err.span_suggestion(
+ assoc_name.span,
+ format!("`{ty_param_name}` has the following associated type"),
+ all_candidate_names.first().unwrap().to_string(),
+ applicability,
+ );
+ } else {
+ err.span_label(assoc_name.span, format!("associated type `{assoc_name}` not found"));
+ }
+
err.emit()
}
@@ -597,7 +622,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
}
- if !suggestions.is_empty() {
+ suggestions.sort_by_key(|&(span, _)| span);
+ // There are cases where one bound points to a span within another bound's span, like when
+ // you have code like the following (#115019), so we skip providing a suggestion in those
+ // cases to avoid having a malformed suggestion.
+ //
+ // pub struct Flatten<I> {
+ // inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::core,
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // | ^^^^^^^^^^^^^^^^^^^^^
+ // | |
+ // | associated types `Item`, `IntoIter` must be specified
+ // associated types `Item`, `IntoIter` must be specified
+ // }
+ let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
+ if !suggestions.is_empty() && !overlaps {
err.multipart_suggestion(
format!("specify the associated type{}", pluralize!(types_count)),
suggestions,
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 1372cc896..e3621ef93 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -139,22 +139,22 @@ fn generic_arg_mismatch_err(
err.emit()
}
-/// Creates the relevant generic argument substitutions
+/// Creates the relevant generic arguments
/// corresponding to a set of generic parameters. This is a
/// rather complex function. Let us try to explain the role
/// of each of its parameters:
///
-/// To start, we are given the `def_id` of the thing we are
-/// creating the substitutions for, and a partial set of
-/// substitutions `parent_args`. In general, the substitutions
-/// for an item begin with substitutions for all the "parents" of
+/// To start, we are given the `def_id` of the thing whose generic
+/// parameters we are instantiating, and a partial set of
+/// arguments `parent_args`. In general, the generic arguments
+/// for an item begin with arguments for all the "parents" of
/// that item -- e.g., for a method it might include the
/// parameters from the impl.
///
/// Therefore, the method begins by walking down these parents,
/// starting with the outermost parent and proceed inwards until
/// it reaches `def_id`. For each parent `P`, it will check `parent_args`
-/// first to see if the parent's substitutions are listed in there. If so,
+/// first to see if the parent's arguments are listed in there. If so,
/// we can append those and move on. Otherwise, it invokes the
/// three callback functions:
///
@@ -188,7 +188,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
stack.push((def_id, parent_defs));
}
- // We manually build up the substitution, rather than using convenience
+ // We manually build up the generic arguments, rather than using convenience
// methods in `subst.rs`, so that we can iterate over the arguments and
// parameters in lock-step linearly, instead of trying to match each pair.
let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
@@ -196,7 +196,8 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
while let Some((def_id, defs)) = stack.pop() {
let mut params = defs.params.iter().peekable();
- // If we have already computed substitutions for parents, we can use those directly.
+ // If we have already computed the generic arguments for parents,
+ // we can use those directly.
while let Some(&param) = params.peek() {
if let Some(&kind) = parent_args.get(param.index as usize) {
args.push(kind);
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 668763f9b..56b1fd369 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -268,9 +268,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// (*) -- not late-bound, won't change
}
- Some(rbv::ResolvedArg::Error(_)) => {
- bug!("only ty/ct should resolve as ResolvedArg::Error")
- }
+ Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
None => {
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
@@ -291,7 +289,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
- /// returns an appropriate set of substitutions for this particular reference to `I`.
+ /// returns an appropriate set of generic arguments for this particular reference to `I`.
pub fn ast_path_args_for_ty(
&self,
span: Span,
@@ -317,7 +315,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Given the type/lifetime/const arguments provided to some path (along with
/// an implicit `Self`, if this is a trait reference), returns the complete
- /// set of substitutions. This may involve applying defaulted type parameters.
+ /// set of generic arguments. This may involve applying defaulted type parameters.
/// Constraints on associated types are created from `create_assoc_bindings_for_generic_args`.
///
/// Example:
@@ -523,7 +521,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ty::new_misc_error(tcx).into()
}
}
- GenericParamDefKind::Const { has_default } => {
+ GenericParamDefKind::Const { has_default, .. } => {
let ty = tcx
.at(self.span)
.type_of(param.def_id)
@@ -910,19 +908,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> Ty<'tcx> {
let tcx = self.tcx();
let args = self.ast_path_args_for_ty(span, did, item_segment);
- let ty = tcx.at(span).type_of(did);
- if let DefKind::TyAlias { lazy } = tcx.def_kind(did)
- && (lazy || ty.skip_binder().has_opaque_types())
+ if let DefKind::TyAlias = tcx.def_kind(did)
+ && tcx.type_alias_is_lazy(did)
{
- // Type aliases referring to types that contain opaque types (but aren't just directly
- // referencing a single opaque type) as well as those defined in crates that have the
+ // Type aliases defined in crates that have the
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
// then actually instantiate the where bounds of.
let alias_ty = tcx.mk_alias_ty(did, args);
Ty::new_alias(tcx, ty::Weak, alias_ty)
} else {
- ty.instantiate(tcx, args)
+ tcx.at(span).type_of(did).instantiate(tcx, args)
}
}
@@ -2161,7 +2157,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Res::Def(
DefKind::Enum
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::Struct
| DefKind::Union
| DefKind::ForeignTy,
@@ -2200,27 +2196,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_note(span, format!("type parameter `{name}` defined here"));
}
});
-
- match tcx.named_bound_var(hir_id) {
- Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
- let name =
- tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
- let br = ty::BoundTy {
- var: ty::BoundVar::from_u32(index),
- kind: ty::BoundTyKind::Param(def_id, name),
- };
- Ty::new_bound(tcx, debruijn, br)
- }
- Some(rbv::ResolvedArg::EarlyBound(_)) => {
- let def_id = def_id.expect_local();
- let item_def_id = tcx.hir().ty_param_owner(def_id);
- let generics = tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
- }
- Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
- arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
- }
+ self.hir_id_to_bound_ty(hir_id)
}
Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
@@ -2389,6 +2365,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
+ // Converts a hir id corresponding to a type parameter to
+ // a early-bound `ty::Param` or late-bound `ty::Bound`.
+ pub(crate) fn hir_id_to_bound_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
+ let tcx = self.tcx();
+ match tcx.named_bound_var(hir_id) {
+ Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
+ let name = tcx.item_name(def_id);
+ let br = ty::BoundTy {
+ var: ty::BoundVar::from_u32(index),
+ kind: ty::BoundTyKind::Param(def_id, name),
+ };
+ Ty::new_bound(tcx, debruijn, br)
+ }
+ Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+ let def_id = def_id.expect_local();
+ let item_def_id = tcx.hir().ty_param_owner(def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+ Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
+ }
+ Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
+ arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
+ }
+ }
+
+ // Converts a hir id corresponding to a const parameter to
+ // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`.
+ pub(crate) fn hir_id_to_bound_const(
+ &self,
+ hir_id: hir::HirId,
+ param_ty: Ty<'tcx>,
+ ) -> Const<'tcx> {
+ let tcx = self.tcx();
+ match tcx.named_bound_var(hir_id) {
+ Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+ // Find the name and index of the const parameter by indexing the generics of
+ // the parent item and construct a `ParamConst`.
+ let item_def_id = tcx.parent(def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = tcx.item_name(def_id);
+ ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)
+ }
+ Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
+ ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty)
+ }
+ Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty),
+ arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
+ }
+ }
+
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
@@ -2747,7 +2774,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
- ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{name}`"),
@@ -2755,7 +2782,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = generate_err(&br_name);
- if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
+ if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 2c7788498..44e1bdb83 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -5,20 +5,17 @@ use super::compare_impl_item::check_type_bounds;
use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*;
use rustc_attr as attr;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ItemKind, Node, PathSegment};
-use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
+use rustc_hir::Node;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
-use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -218,9 +215,6 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
let args = GenericArgs::identity_for_item(tcx, item.owner_id);
let span = tcx.def_span(item.owner_id.def_id);
- if !tcx.features().impl_trait_projections {
- check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
- }
if tcx.type_of(item.owner_id.def_id).instantiate_identity().references_error() {
return;
}
@@ -231,129 +225,6 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, 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))]
-pub(super) fn check_opaque_for_inheriting_lifetimes(
- tcx: TyCtxt<'_>,
- def_id: LocalDefId,
- span: Span,
-) {
- let item = tcx.hir().expect_item(def_id);
- debug!(?item, ?span);
-
- struct ProhibitOpaqueVisitor<'tcx> {
- tcx: TyCtxt<'tcx>,
- opaque_identity_ty: Ty<'tcx>,
- parent_count: u32,
- references_parent_regions: bool,
- selftys: Vec<(Span, Option<String>)>,
- }
-
- impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueVisitor<'tcx> {
- type BreakTy = Ty<'tcx>;
-
- fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- debug!(?t, "root_visit_ty");
- if t == self.opaque_identity_ty {
- ControlFlow::Continue(())
- } else {
- t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx: self.tcx,
- op: |region| {
- if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *region
- && index < self.parent_count
- {
- self.references_parent_regions= true;
- }
- },
- });
- if self.references_parent_regions {
- ControlFlow::Break(t)
- } else {
- ControlFlow::Continue(())
- }
- }
- }
- }
-
- impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
- type NestedFilter = nested_filter::OnlyBodies;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
-
- 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::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));
- }
- _ => {}
- },
- _ => {}
- }
- hir::intravisit::walk_ty(self, arg);
- }
- }
-
- if let ItemKind::OpaqueTy(&hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
- ..
- }) = item.kind
- {
- let args = GenericArgs::identity_for_item(tcx, def_id);
- let opaque_identity_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
- let mut visitor = ProhibitOpaqueVisitor {
- opaque_identity_ty,
- parent_count: tcx.generics_of(def_id).parent_count as u32,
- references_parent_regions: false,
- tcx,
- selftys: vec![],
- };
- let prohibit_opaque = tcx
- .explicit_item_bounds(def_id)
- .instantiate_identity_iter_copied()
- .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
-
- if let Some(ty) = prohibit_opaque.break_value() {
- visitor.visit_item(&item);
- let is_async = match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
- matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..))
- }
- _ => unreachable!(),
- };
-
- let mut err = feature_err(
- &tcx.sess.parse_sess,
- sym::impl_trait_projections,
- span,
- format!(
- "`{}` return type cannot contain a projection or `Self` that references \
- lifetimes from a parent scope",
- if is_async { "async fn" } else { "impl Trait" },
- ),
- );
- for (span, name) in visitor.selftys {
- err.span_suggestion(
- span,
- "consider spelling out the type instead",
- name.unwrap_or_else(|| format!("{ty:?}")),
- Applicability::MaybeIncorrect,
- );
- }
- err.emit();
- }
- }
-}
-
/// Checks that an opaque type does not contain cycles.
pub(super) fn check_opaque_for_cycles<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -640,7 +511,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
check_opaque(tcx, id);
}
}
- DefKind::TyAlias { .. } => {
+ DefKind::TyAlias => {
let pty_ty = tcx.type_of(id.owner_id).instantiate_identity();
let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);
@@ -831,7 +702,7 @@ fn check_impl_items_against_trait<'tcx>(
};
match ty_impl_item.kind {
ty::AssocKind::Const => {
- let _ = tcx.compare_impl_const((
+ tcx.ensure().compare_impl_const((
impl_item.expect_local(),
ty_impl_item.trait_item_def_id.unwrap(),
));
@@ -1138,19 +1009,19 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return;
}
- // For each field, figure out if it's known to be a ZST and align(1), with "known"
- // respecting #[non_exhaustive] attributes.
+ // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
+ // "known" respecting #[non_exhaustive] attributes.
let field_infos = adt.all_fields().map(|field| {
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
- let zst = layout.is_ok_and(|layout| layout.is_zst());
- let align = layout.ok().map(|layout| layout.align.abi.bytes());
- if !zst {
- return (span, zst, align, None);
+ let trivial = layout.is_ok_and(|layout| layout.is_1zst());
+ if !trivial {
+ return (span, trivial, None);
}
+ // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
fn check_non_exhaustive<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -1184,58 +1055,52 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
}
- (span, zst, align, check_non_exhaustive(tcx, ty).break_value())
+ (span, trivial, check_non_exhaustive(tcx, ty).break_value())
});
- let non_zst_fields = field_infos
+ let non_trivial_fields = field_infos
.clone()
- .filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
- let non_zst_count = non_zst_fields.clone().count();
- if non_zst_count >= 2 {
- bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
+ .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
+ let non_trivial_count = non_trivial_fields.clone().count();
+ if non_trivial_count >= 2 {
+ bad_non_zero_sized_fields(
+ tcx,
+ adt,
+ non_trivial_count,
+ non_trivial_fields,
+ tcx.def_span(adt.did()),
+ );
+ return;
}
- let incompatible_zst_fields =
- field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
- let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
- for (span, zst, align, non_exhaustive) in field_infos {
- if zst && align != Some(1) {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0691,
- "zero-sized field in transparent {} has alignment larger than 1",
- adt.descr(),
- );
-
- if let Some(align_bytes) = align {
- err.span_label(
+ let mut prev_non_exhaustive_1zst = false;
+ for (span, _trivial, non_exhaustive_1zst) in field_infos {
+ if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
+ // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
+ // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
+ if non_trivial_count > 0 || prev_non_exhaustive_1zst {
+ tcx.struct_span_lint_hir(
+ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+ tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
- format!("has alignment of {align_bytes}, which is larger than 1"),
- );
+ "zero-sized fields in `repr(transparent)` cannot \
+ contain external non-exhaustive types",
+ |lint| {
+ let note = if non_exhaustive {
+ "is marked with `#[non_exhaustive]`"
+ } else {
+ "contains private fields"
+ };
+ let field_ty = tcx.def_path_str_with_args(def_id, args);
+ 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."
+ ))
+ },
+ )
} else {
- err.span_label(span, "may have alignment larger than 1");
+ prev_non_exhaustive_1zst = true;
}
-
- err.emit();
- }
- if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
- tcx.struct_span_lint_hir(
- 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]`"
- } else {
- "contains private fields"
- };
- let field_ty = tcx.def_path_str_with_args(def_id, args);
- 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."))
- },
- )
}
}
}
@@ -1585,13 +1450,7 @@ fn opaque_type_cycle_error(
label_match(capture.place.ty(), capture.get_path_span(tcx));
}
// Label any generator locals that capture the opaque
- for interior_ty in
- typeck_results.generator_interior_types.as_ref().skip_binder()
- {
- label_match(interior_ty.ty, interior_ty.span);
- }
- if tcx.sess.opts.unstable_opts.drop_tracking_mir
- && let DefKind::Generator = tcx.def_kind(closure_def_id)
+ if let DefKind::Generator = tcx.def_kind(closure_def_id)
&& let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
{
for interior_ty in &generator_layout.field_tys {
@@ -1609,7 +1468,6 @@ fn opaque_type_cycle_error(
}
pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
let typeck = tcx.typeck(def_id);
@@ -1632,6 +1490,25 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
+
+ if (tcx.features().unsized_locals || tcx.features().unsized_fn_params)
+ && let Some(generator) = tcx.mir_generator_witnesses(def_id)
+ {
+ for field_ty in generator.field_tys.iter() {
+ fulfillment_cx.register_bound(
+ &infcx,
+ param_env,
+ field_ty.ty,
+ tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
+ ObligationCause::new(
+ field_ty.source_info.span,
+ def_id,
+ ObligationCauseCode::SizedGeneratorInterior(def_id),
+ ),
+ );
+ }
+ }
+
let errors = fulfillment_cx.select_all_or_error(&infcx);
debug!(?errors);
if !errors.is_empty() {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index bd0ab6463..d081b0e35 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -14,11 +14,12 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::util::ExplicitSelf;
use rustc_middle::ty::{
self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
-use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
+use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -28,6 +29,8 @@ use rustc_trait_selection::traits::{
use std::borrow::Cow;
use std::iter;
+mod refine;
+
/// Checks that a method from an impl conforms to the signature of
/// the same method as declared in the trait.
///
@@ -53,6 +56,12 @@ pub(super) fn compare_impl_method<'tcx>(
impl_trait_ref,
CheckImpliedWfMode::Check,
)?;
+ refine::check_refining_return_position_impl_trait_in_trait(
+ tcx,
+ impl_m,
+ trait_m,
+ impl_trait_ref,
+ );
};
}
@@ -587,7 +596,7 @@ fn compare_asyncness<'tcx>(
trait_m: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
- if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+ if tcx.asyncness(trait_m.def_id).is_async() {
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
ty::Alias(ty::Opaque, ..) => {
// allow both `async fn foo()` and `fn foo() -> impl Future`
@@ -653,8 +662,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
- let param_env = tcx.param_env(impl_m_def_id);
-
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during substitution later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
@@ -680,13 +687,26 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let trait_to_placeholder_args =
impl_to_placeholder_args.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_args);
+ let hybrid_preds = tcx
+ .predicates_of(impl_m.container_id(tcx))
+ .instantiate_identity(tcx)
+ .into_iter()
+ .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args))
+ .map(|(clause, _)| clause);
+ let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
+ let param_env = traits::normalize_param_env_or_error(
+ tcx,
+ param_env,
+ ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id),
+ );
+
let infcx = &tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(infcx);
// Normalize the impl signature with fresh variables for lifetime inference.
- let norm_cause = ObligationCause::misc(return_span, impl_m_def_id);
+ let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);
let impl_sig = ocx.normalize(
- &norm_cause,
+ &misc_cause,
param_env,
tcx.liberate_late_bound_regions(
impl_m.def_id,
@@ -717,12 +737,68 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
);
}
- let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
+ let trait_sig = ocx.normalize(&misc_cause, param_env, unnormalized_trait_sig);
trait_sig.error_reported()?;
let trait_return_ty = trait_sig.output();
+ // RPITITs are allowed to use the implied predicates of the method that
+ // defines them. This is because we want code like:
+ // ```
+ // trait Foo {
+ // fn test<'a, T>(_: &'a T) -> impl Sized;
+ // }
+ // impl Foo for () {
+ // fn test<'a, T>(x: &'a T) -> &'a T { x }
+ // }
+ // ```
+ // .. to compile. However, since we use both the normalized and unnormalized
+ // inputs and outputs from the substituted trait signature, we will end up
+ // seeing the hidden type of an RPIT in the signature itself. Naively, this
+ // means that we will use the hidden type to imply the hidden type's own
+ // well-formedness.
+ //
+ // To avoid this, we replace the infer vars used for hidden type inference
+ // with placeholders, which imply nothing about outlives bounds, and then
+ // prove below that the hidden types are well formed.
+ let universe = infcx.create_next_universe();
+ let mut idx = 0;
+ let mapping: FxHashMap<_, _> = collector
+ .types
+ .iter()
+ .map(|(_, &(ty, _))| {
+ assert!(
+ infcx.resolve_vars_if_possible(ty) == ty && ty.is_ty_var(),
+ "{ty:?} should not have been constrained via normalization",
+ ty = infcx.resolve_vars_if_possible(ty)
+ );
+ idx += 1;
+ (
+ ty,
+ Ty::new_placeholder(
+ tcx,
+ ty::Placeholder {
+ universe,
+ bound: ty::BoundTy {
+ var: ty::BoundVar::from_usize(idx),
+ kind: ty::BoundTyKind::Anon,
+ },
+ },
+ ),
+ )
+ })
+ .collect();
+ let mut type_mapper = BottomUpFolder {
+ tcx,
+ ty_op: |ty| *mapping.get(&ty).unwrap_or(&ty),
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ };
let wf_tys = FxIndexSet::from_iter(
- unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
+ unnormalized_trait_sig
+ .inputs_and_output
+ .iter()
+ .chain(trait_sig.inputs_and_output.iter())
+ .map(|ty| ty.fold_with(&mut type_mapper)),
);
match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
@@ -779,6 +855,20 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
}
}
+ // FIXME: This has the same issue as #108544, but since this isn't breaking
+ // existing code, I'm not particularly inclined to do the same hack as above
+ // where we process wf obligations manually. This can be fixed in a forward-
+ // compatible way later.
+ let collected_types = collector.types;
+ for (_, &(ty, _)) in &collected_types {
+ ocx.register_obligation(traits::Obligation::new(
+ tcx,
+ misc_cause.clone(),
+ param_env,
+ ty::ClauseKind::WellFormed(ty.into()),
+ ));
+ }
+
// Check that all obligations are satisfied by the implementation's
// RPITs.
let errors = ocx.select_all_or_error();
@@ -787,8 +877,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
return Err(reported);
}
- let collected_types = collector.types;
-
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let outlives_env = OutlivesEnvironment::with_bounds(
@@ -1126,7 +1214,10 @@ fn report_trait_method_mismatch<'tcx>(
&mut diag,
&cause,
trait_err_span.map(|sp| (sp, Cow::from("type in trait"))),
- Some(infer::ValuePairs::Sigs(ExpectedFound { expected: trait_sig, found: impl_sig })),
+ Some(infer::ValuePairs::PolySigs(ExpectedFound {
+ expected: ty::Binder::dummy(trait_sig),
+ found: ty::Binder::dummy(impl_sig),
+ })),
terr,
false,
false,
@@ -2188,16 +2279,16 @@ pub(super) fn check_type_bounds<'tcx>(
//
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
}
- _ => predicates.push(
+ _ => predicates.push(ty::Clause::from_projection_clause(
+ tcx,
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args),
term: normalize_impl_ty.into(),
},
bound_vars,
- )
- .to_predicate(tcx),
- ),
+ ),
+ )),
};
ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing)
};
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
new file mode 100644
index 000000000..d9e0e87eb
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -0,0 +1,332 @@
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
+use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT;
+use rustc_middle::traits::{ObligationCause, Reveal};
+use rustc_middle::ty::{
+ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+};
+use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::traits::{
+ elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt,
+};
+use std::ops::ControlFlow;
+
+/// Check that an implementation does not refine an RPITIT from a trait method signature.
+pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: ty::AssocItem,
+ trait_m: ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) {
+ if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) {
+ return;
+ }
+ // crate-private traits don't have any library guarantees, there's no need to do this check.
+ if !tcx.visibility(trait_m.container_id(tcx)).is_public() {
+ return;
+ }
+
+ // If a type in the trait ref is private, then there's also no reason to to do this check.
+ let impl_def_id = impl_m.container_id(tcx);
+ for arg in impl_trait_ref.args {
+ if let Some(ty) = arg.as_type()
+ && let Some(self_visibility) = type_visibility(tcx, ty)
+ && !self_visibility.is_public()
+ {
+ return;
+ }
+ }
+
+ let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id);
+ let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args);
+ let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args);
+ let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig);
+ // replace the self type of the trait ref with `Self` so that diagnostics render better.
+ let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions(
+ impl_m.def_id,
+ tcx.fn_sig(trait_m.def_id).instantiate(
+ tcx,
+ tcx.mk_args_from_iter(
+ [tcx.types.self_param.into()]
+ .into_iter()
+ .chain(trait_m_to_impl_m_args.iter().skip(1)),
+ ),
+ ),
+ );
+
+ let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else {
+ // Error already emitted, no need to delay another.
+ return;
+ };
+
+ let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() };
+ trait_m_sig.visit_with(&mut collector);
+
+ // Bound that we find on RPITITs in the trait signature.
+ let mut trait_bounds = vec![];
+ // Bounds that we find on the RPITITs in the impl signature.
+ let mut impl_bounds = vec![];
+
+ for trait_projection in collector.types.into_iter().rev() {
+ let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
+ let hidden_ty = hidden_tys[&trait_projection.def_id].instantiate(tcx, impl_opaque_args);
+
+ // If the hidden type is not an opaque, then we have "refined" the trait signature.
+ let ty::Alias(ty::Opaque, impl_opaque) = *hidden_ty.kind() else {
+ report_mismatched_rpitit_signature(
+ tcx,
+ trait_m_sig_with_self_for_diag,
+ trait_m.def_id,
+ impl_m.def_id,
+ None,
+ );
+ return;
+ };
+
+ // This opaque also needs to be from the impl method -- otherwise,
+ // it's a refinement to a TAIT.
+ if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| {
+ matches!(
+ node.expect_item().expect_opaque_ty().origin,
+ hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id)
+ if def_id == impl_m.def_id.expect_local()
+ )
+ }) {
+ report_mismatched_rpitit_signature(
+ tcx,
+ trait_m_sig_with_self_for_diag,
+ trait_m.def_id,
+ impl_m.def_id,
+ None,
+ );
+ return;
+ }
+
+ trait_bounds.extend(
+ tcx.item_bounds(trait_projection.def_id).iter_instantiated(tcx, trait_projection.args),
+ );
+ impl_bounds.extend(elaborate(
+ tcx,
+ tcx.explicit_item_bounds(impl_opaque.def_id)
+ .iter_instantiated_copied(tcx, impl_opaque.args),
+ ));
+ }
+
+ let hybrid_preds = tcx
+ .predicates_of(impl_def_id)
+ .instantiate_identity(tcx)
+ .into_iter()
+ .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args))
+ .map(|(clause, _)| clause);
+ let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
+ let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy());
+
+ let ref infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+
+ // Normalize the bounds. This has two purposes:
+ //
+ // 1. Project the RPITIT projections from the trait to the opaques on the impl,
+ // which means that they don't need to be mapped manually.
+ //
+ // 2. Project any other projections that show up in the bound. That makes sure that
+ // we don't consider `tests/ui/async-await/in-trait/async-associated-types.rs`
+ // to be refining.
+ let (trait_bounds, impl_bounds) =
+ ocx.normalize(&ObligationCause::dummy(), param_env, (trait_bounds, impl_bounds));
+
+ // Since we've normalized things, we need to resolve regions, since we'll
+ // possibly have introduced region vars during projection. We don't expect
+ // this resolution to have incurred any region errors -- but if we do, then
+ // just delay a bug.
+ let mut implied_wf_types = FxIndexSet::default();
+ implied_wf_types.extend(trait_m_sig.inputs_and_output);
+ implied_wf_types.extend(ocx.normalize(
+ &ObligationCause::dummy(),
+ param_env,
+ trait_m_sig.inputs_and_output,
+ ));
+ if !ocx.select_all_or_error().is_empty() {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ "encountered errors when checking RPITIT refinement (selection)",
+ );
+ return;
+ }
+ let outlives_env = OutlivesEnvironment::with_bounds(
+ param_env,
+ infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
+ );
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ "encountered errors when checking RPITIT refinement (regions)",
+ );
+ return;
+ }
+ // Resolve any lifetime variables that may have been introduced during normalization.
+ let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ "encountered errors when checking RPITIT refinement (resolution)",
+ );
+ return;
+ };
+
+ // For quicker lookup, use an `IndexSet` (we don't use one earlier because
+ // it's not foldable..).
+ // Also, We have to anonymize binders in these types because they may contain
+ // `BrNamed` bound vars, which contain unique `DefId`s which correspond to syntax
+ // locations that we don't care about when checking bound equality.
+ let trait_bounds = FxIndexSet::from_iter(trait_bounds.fold_with(&mut Anonymize { tcx }));
+ let impl_bounds = impl_bounds.fold_with(&mut Anonymize { tcx });
+
+ // Find any clauses that are present in the impl's RPITITs that are not
+ // present in the trait's RPITITs. This will trigger on trivial predicates,
+ // too, since we *do not* use the trait solver to prove that the RPITIT's
+ // bounds are not stronger -- we're doing a simple, syntactic compatibility
+ // check between bounds. This is strictly forwards compatible, though.
+ for (clause, span) in impl_bounds {
+ if !trait_bounds.contains(&clause) {
+ report_mismatched_rpitit_signature(
+ tcx,
+ trait_m_sig_with_self_for_diag,
+ trait_m.def_id,
+ impl_m.def_id,
+ Some(span),
+ );
+ return;
+ }
+ }
+}
+
+struct ImplTraitInTraitCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ types: FxIndexSet<ty::AliasTy<'tcx>>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'tcx> {
+ type BreakTy = !;
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+ if let ty::Alias(ty::Projection, proj) = *ty.kind()
+ && self.tcx.is_impl_trait_in_trait(proj.def_id)
+ {
+ if self.types.insert(proj) {
+ for (pred, _) in self
+ .tcx
+ .explicit_item_bounds(proj.def_id)
+ .iter_instantiated_copied(self.tcx, proj.args)
+ {
+ pred.visit_with(self)?;
+ }
+ }
+ ControlFlow::Continue(())
+ } else {
+ ty.super_visit_with(self)
+ }
+ }
+}
+
+fn report_mismatched_rpitit_signature<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_m_sig: ty::FnSig<'tcx>,
+ trait_m_def_id: DefId,
+ impl_m_def_id: DefId,
+ unmatched_bound: Option<Span>,
+) {
+ let mapping = std::iter::zip(
+ tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(),
+ tcx.fn_sig(impl_m_def_id).skip_binder().bound_vars(),
+ )
+ .filter_map(|(impl_bv, trait_bv)| {
+ if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
+ && let ty::BoundVariableKind::Region(trait_bv) = trait_bv
+ {
+ Some((impl_bv, trait_bv))
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ let mut return_ty =
+ trait_m_sig.output().fold_with(&mut super::RemapLateBound { tcx, mapping: &mapping });
+
+ if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() {
+ let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else {
+ bug!();
+ };
+ let Some(future_output_ty) = tcx
+ .explicit_item_bounds(future_ty.def_id)
+ .iter_instantiated_copied(tcx, future_ty.args)
+ .find_map(|(clause, _)| match clause.kind().no_bound_vars()? {
+ ty::ClauseKind::Projection(proj) => proj.term.ty(),
+ _ => None,
+ })
+ else {
+ bug!()
+ };
+ return_ty = future_output_ty;
+ }
+
+ let (span, impl_return_span, pre, post) =
+ match tcx.hir().get_by_def_id(impl_m_def_id.expect_local()).fn_decl().unwrap().output {
+ hir::FnRetTy::DefaultReturn(span) => (tcx.def_span(impl_m_def_id), span, "-> ", " "),
+ hir::FnRetTy::Return(ty) => (ty.span, ty.span, "", ""),
+ };
+ let trait_return_span =
+ tcx.hir().get_if_local(trait_m_def_id).map(|node| match node.fn_decl().unwrap().output {
+ hir::FnRetTy::DefaultReturn(_) => tcx.def_span(trait_m_def_id),
+ hir::FnRetTy::Return(ty) => ty.span,
+ });
+
+ let span = unmatched_bound.unwrap_or(span);
+ tcx.emit_spanned_lint(
+ REFINING_IMPL_TRAIT,
+ tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()),
+ span,
+ crate::errors::ReturnPositionImplTraitInTraitRefined {
+ impl_return_span,
+ trait_return_span,
+ pre,
+ post,
+ return_ty,
+ unmatched_bound,
+ },
+ );
+}
+
+fn type_visibility<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<ty::Visibility<DefId>> {
+ match *ty.kind() {
+ ty::Ref(_, ty, _) => type_visibility(tcx, ty),
+ ty::Adt(def, args) => {
+ if def.is_fundamental() {
+ type_visibility(tcx, args.type_at(0))
+ } else {
+ Some(tcx.visibility(def.did()))
+ }
+ }
+ _ => None,
+ }
+}
+
+struct Anonymize<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+ where
+ T: TypeFoldable<TyCtxt<'tcx>>,
+ {
+ self.tcx.anonymize_bound_vars(t)
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index fcaefe026..3cd3f5bcf 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -11,8 +11,8 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::ops::Not;
+use super::check_function_signature;
use crate::errors;
-use crate::require_same_types;
pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
match tcx.entry_fn(()) {
@@ -112,7 +112,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
let main_asyncness = tcx.asyncness(main_def_id);
- if let hir::IsAsync::Async = main_asyncness {
+ if main_asyncness.is_async() {
let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
error = true;
@@ -162,33 +162,33 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true;
}
// now we can take the return type of the given main function
- expected_return_type = main_fnsig.output();
+ expected_return_type = norm_return_ty;
} else {
// standard () main return type
- expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
+ expected_return_type = tcx.types.unit;
}
if error {
return;
}
- let se_ty = Ty::new_fn_ptr(
- tcx,
- expected_return_type.map_bound(|expected_return_type| {
- tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
- }),
- );
+ let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+ [],
+ expected_return_type,
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust,
+ ));
- require_same_types(
+ check_function_signature(
tcx,
- &ObligationCause::new(
+ ObligationCause::new(
main_span,
main_diagnostics_def_id,
ObligationCauseCode::MainFunctionType,
),
- param_env,
- se_ty,
- Ty::new_fn_ptr(tcx, main_fnsig),
+ main_def_id,
+ expected_sig,
);
}
@@ -212,7 +212,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
});
error = true;
}
- if let hir::IsAsync::Async = sig.header.asyncness {
+ if sig.header.asyncness.is_async() {
let span = tcx.def_span(it.owner_id);
tcx.sess.emit_err(errors::StartAsync { span: span });
error = true;
@@ -247,27 +247,23 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
}
}
- let se_ty = Ty::new_fn_ptr(
- tcx,
- ty::Binder::dummy(tcx.mk_fn_sig(
- [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
- tcx.types.isize,
- false,
- hir::Unsafety::Normal,
- Abi::Rust,
- )),
- );
+ let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
+ [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
+ tcx.types.isize,
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust,
+ ));
- require_same_types(
+ check_function_signature(
tcx,
- &ObligationCause::new(
+ ObligationCause::new(
start_span,
start_def_id,
ObligationCauseCode::StartFunctionType,
),
- ty::ParamEnv::empty(), // start should not have any where bounds.
- se_ty,
- Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()),
+ start_def_id.into(),
+ expected_sig,
);
}
_ => {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f89e2e5c2..c61719c1f 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -1,11 +1,11 @@
//! Type-checking for the rust-intrinsic and platform-intrinsic
//! intrinsics that the compiler exposes.
+use crate::check::check_function_signature;
use crate::errors::{
UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
WrongNumberOfGenericArgumentsToIntrinsic,
};
-use crate::require_same_types;
use hir::def_id::DefId;
use rustc_errors::{struct_span_err, DiagnosticMessage};
@@ -20,6 +20,7 @@ fn equate_intrinsic_type<'tcx>(
it: &hir::ForeignItem<'_>,
n_tps: usize,
n_lts: usize,
+ n_cts: usize,
sig: ty::PolyFnSig<'tcx>,
) {
let (own_counts, span) = match &it.kind {
@@ -51,17 +52,14 @@ fn equate_intrinsic_type<'tcx>(
if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
&& gen_count_ok(own_counts.types, n_tps, "type")
- && gen_count_ok(own_counts.consts, 0, "const")
+ && gen_count_ok(own_counts.consts, n_cts, "const")
{
- let fty = Ty::new_fn_ptr(tcx, sig);
let it_def_id = it.owner_id.def_id;
- let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType);
- require_same_types(
+ check_function_signature(
tcx,
- &cause,
- ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
- Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).instantiate_identity()),
- fty,
+ ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType),
+ it_def_id.into(),
+ sig,
);
}
}
@@ -140,7 +138,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(&[
- ty::BoundVariableKind::Region(ty::BrAnon(None)),
+ ty::BoundVariableKind::Region(ty::BrAnon),
ty::BoundVariableKind::Region(ty::BrEnv),
]);
let mk_va_list_ty = |mutbl| {
@@ -148,7 +146,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let region = ty::Region::new_late_bound(
tcx,
ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon },
);
let env_region = ty::Region::new_late_bound(
tcx,
@@ -408,7 +406,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
);
let discriminant_def_id = assoc_items[0];
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
+ let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
(
1,
vec![Ty::new_imm_ref(
@@ -466,7 +464,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
}
sym::raw_eq => {
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
+ let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
let param_ty = Ty::new_imm_ref(
tcx,
ty::Region::new_late_bound(tcx, ty::INNERMOST, br),
@@ -492,7 +490,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
};
let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic);
let sig = ty::Binder::bind_with_vars(sig, bound_vars);
- equate_intrinsic_type(tcx, it, n_tps, n_lts, sig)
+ equate_intrinsic_type(tcx, it, n_tps, n_lts, 0, sig)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -504,9 +502,9 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
let name = it.ident.name;
- let (n_tps, inputs, output) = match name {
+ let (n_tps, n_cts, inputs, output) = match name {
sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
- (2, vec![param(0), param(0)], param(1))
+ (2, 0, vec![param(0), param(0)], param(1))
}
sym::simd_add
| sym::simd_sub
@@ -522,8 +520,8 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
| sym::simd_fmax
| sym::simd_fpow
| sym::simd_saturating_add
- | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)),
- sym::simd_arith_offset => (2, vec![param(0), param(1)], param(0)),
+ | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)),
+ sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)),
sym::simd_neg
| sym::simd_bswap
| sym::simd_bitreverse
@@ -541,25 +539,25 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
| sym::simd_ceil
| sym::simd_floor
| sym::simd_round
- | sym::simd_trunc => (1, vec![param(0)], param(0)),
- sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)),
- sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)),
- sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)),
- sym::simd_scatter => (3, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
- sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
- sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
+ | sym::simd_trunc => (1, 0, vec![param(0)], param(0)),
+ sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)),
+ sym::simd_fma => (1, 0, vec![param(0), param(0), param(0)], param(0)),
+ sym::simd_gather => (3, 0, vec![param(0), param(1), param(2)], param(0)),
+ sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
+ sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)),
+ sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)),
sym::simd_cast
| sym::simd_as
| sym::simd_cast_ptr
| sym::simd_expose_addr
- | sym::simd_from_exposed_addr => (2, vec![param(0)], param(1)),
- sym::simd_bitmask => (2, vec![param(0)], param(1)),
+ | sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)),
+ sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
sym::simd_select | sym::simd_select_bitmask => {
- (2, vec![param(0), param(1), param(1)], param(1))
+ (2, 0, vec![param(0), param(1), param(1)], param(1))
}
- sym::simd_reduce_all | sym::simd_reduce_any => (1, vec![param(0)], tcx.types.bool),
+ sym::simd_reduce_all | sym::simd_reduce_any => (1, 0, vec![param(0)], tcx.types.bool),
sym::simd_reduce_add_ordered | sym::simd_reduce_mul_ordered => {
- (2, vec![param(0), param(1)], param(1))
+ (2, 0, vec![param(0), param(1)], param(1))
}
sym::simd_reduce_add_unordered
| sym::simd_reduce_mul_unordered
@@ -569,8 +567,9 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
| sym::simd_reduce_min
| sym::simd_reduce_max
| sym::simd_reduce_min_nanless
- | sym::simd_reduce_max_nanless => (2, vec![param(0)], param(1)),
- sym::simd_shuffle => (3, vec![param(0), param(0), param(1)], param(2)),
+ | sym::simd_reduce_max_nanless => (2, 0, vec![param(0)], param(1)),
+ sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
+ sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
_ => {
let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
tcx.sess.struct_span_err(it.span, msg).emit();
@@ -580,5 +579,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
let sig = tcx.mk_fn_sig(inputs, output, false, hir::Unsafety::Unsafe, Abi::PlatformIntrinsic);
let sig = ty::Binder::dummy(sig);
- equate_intrinsic_type(tcx, it, n_tps, 0, sig)
+ equate_intrinsic_type(tcx, it, n_tps, 0, n_cts, sig)
}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 945953edd..cd7e99172 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -44,20 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
false
}
- fn check_asm_operand_type(
- &self,
- idx: usize,
- reg: InlineAsmRegOrRegClass,
- expr: &'tcx hir::Expr<'tcx>,
- template: &[InlineAsmTemplatePiece],
- is_input: bool,
- tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
- target_features: &FxIndexSet<Symbol>,
- ) -> Option<InlineAsmType> {
- let ty = (self.get_operand_ty)(expr);
- if ty.has_non_region_infer() {
- bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
- }
+ fn get_asm_ty(&self, ty: Ty<'tcx>) -> Option<InlineAsmType> {
let asm_ty_isize = match self.tcx.sess.target.pointer_width {
16 => InlineAsmType::I16,
32 => InlineAsmType::I32,
@@ -65,10 +52,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
_ => unreachable!(),
};
- let asm_ty = match *ty.kind() {
- // `!` is allowed for input but not for output (issue #87802)
- ty::Never if is_input => return None,
- _ if ty.references_error() => return None,
+ match *ty.kind() {
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
@@ -99,7 +83,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
};
match ty.kind() {
- ty::Never | ty::Error(_) => return None,
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => {
Some(InlineAsmType::VecI16(size))
@@ -128,6 +111,38 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
ty::Infer(_) => unreachable!(),
_ => None,
+ }
+ }
+
+ fn check_asm_operand_type(
+ &self,
+ idx: usize,
+ reg: InlineAsmRegOrRegClass,
+ expr: &'tcx hir::Expr<'tcx>,
+ template: &[InlineAsmTemplatePiece],
+ is_input: bool,
+ tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
+ target_features: &FxIndexSet<Symbol>,
+ ) -> Option<InlineAsmType> {
+ let ty = (self.get_operand_ty)(expr);
+ if ty.has_non_region_infer() {
+ bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
+ }
+
+ let asm_ty = match *ty.kind() {
+ // `!` is allowed for input but not for output (issue #87802)
+ ty::Never if is_input => return None,
+ _ if ty.references_error() => return None,
+ ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => {
+ let fields = &adt.non_enum_variant().fields;
+ let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args);
+ let ty::Adt(ty, args) = ty.kind() else { unreachable!() };
+ assert!(ty.is_manually_drop());
+ let fields = &ty.non_enum_variant().fields;
+ let ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
+ self.get_asm_ty(ty)
+ }
+ _ => self.get_asm_ty(ty),
};
let Some(asm_ty) = asm_ty else {
let msg = format!("cannot use value of type `{ty}` for inline assembly");
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4cf358732..5fa65f33c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -73,23 +73,31 @@ pub mod wfcheck;
pub use check::check_abi;
+use std::num::NonZeroU32;
+
use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{self, TyCtxtInferExt as _};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::query::Providers;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
use rustc_session::parse::feature_err;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, BytePos, Span, Symbol};
+use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use std::num::NonZeroU32;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::ObligationCtxt;
use crate::errors;
use crate::require_c_abi_if_c_variadic;
@@ -289,6 +297,7 @@ fn default_body_is_unstable(
&tcx.sess.parse_sess,
feature,
rustc_feature::GateIssue::Library(issue),
+ false,
);
err.emit();
@@ -320,41 +329,52 @@ fn bounds_from_generic_predicates<'tcx>(
_ => {}
}
}
- let generics = if types.is_empty() {
- "".to_string()
- } else {
- format!(
- "<{}>",
- types
- .keys()
- .filter_map(|t| match t.kind() {
- ty::Param(_) => Some(t.to_string()),
- // Avoid suggesting the following:
- // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
- _ => None,
- })
- .collect::<Vec<_>>()
- .join(", ")
- )
- };
+
let mut where_clauses = vec![];
+ let mut types_str = vec![];
for (ty, bounds) in types {
- where_clauses
- .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
- }
- for projection in &projections {
- let p = projection.skip_binder();
- // FIXME: this is not currently supported syntax, we should be looking at the `types` and
- // insert the associated types where they correspond, but for now let's be "lazy" and
- // propose this instead of the following valid resugaring:
- // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
- where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
+ if let ty::Param(_) = ty.kind() {
+ let mut bounds_str = vec![];
+ for bound in bounds {
+ let mut projections_str = vec![];
+ for projection in &projections {
+ let p = projection.skip_binder();
+ let alias_ty = p.projection_ty;
+ if bound == tcx.parent(alias_ty.def_id) && alias_ty.self_ty() == ty {
+ let name = tcx.item_name(alias_ty.def_id);
+ projections_str.push(format!("{} = {}", name, p.term));
+ }
+ }
+ let bound_def_path = tcx.def_path_str(bound);
+ if projections_str.is_empty() {
+ where_clauses.push(format!("{}: {}", ty, bound_def_path));
+ } else {
+ bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
+ }
+ }
+ if bounds_str.is_empty() {
+ types_str.push(ty.to_string());
+ } else {
+ types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
+ }
+ } else {
+ // Avoid suggesting the following:
+ // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
+ where_clauses.extend(
+ bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
+ );
+ }
}
+
+ let generics =
+ if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
+
let where_clauses = if where_clauses.is_empty() {
- String::new()
+ "".to_string()
} else {
format!(" where {}", where_clauses.join(", "))
};
+
(generics, where_clauses)
}
@@ -545,3 +565,76 @@ fn bad_non_zero_sized_fields<'tcx>(
pub fn potentially_plural_count(count: usize, word: &str) -> String {
format!("{} {}{}", count, word, pluralize!(count))
}
+
+pub fn check_function_signature<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ fn_id: DefId,
+ expected_sig: ty::PolyFnSig<'tcx>,
+) {
+ let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
+
+ let param_env = ty::ParamEnv::empty();
+
+ let infcx = &tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(infcx);
+
+ let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
+
+ let norm_cause = ObligationCause::misc(cause.span, local_id);
+ let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
+
+ match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
+ Ok(()) => {
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors);
+ return;
+ }
+ }
+ Err(err) => {
+ let err_ctxt = infcx.err_ctxt();
+ if fn_id.is_local() {
+ cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
+ }
+ let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
+ let mut diag = tcx.sess.create_err(failure_code);
+ err_ctxt.note_type_err(
+ &mut diag,
+ &cause,
+ None,
+ Some(infer::ValuePairs::PolySigs(ExpectedFound {
+ expected: expected_sig,
+ found: actual_sig,
+ })),
+ err,
+ false,
+ false,
+ );
+ diag.emit();
+ return;
+ }
+ }
+
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env);
+
+ fn extract_span_for_error_reporting<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ err: TypeError<'_>,
+ cause: &ObligationCause<'tcx>,
+ fn_id: LocalDefId,
+ ) -> rustc_span::Span {
+ let mut args = {
+ let node = tcx.hir().expect_owner(fn_id);
+ let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
+ decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
+ };
+
+ match err {
+ TypeError::ArgumentMutability(i)
+ | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
+ _ => cause.span(),
+ }
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 5bd6fcb96..463fab93e 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -149,7 +149,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
// From now on, we continue normally.
visitor.cx = prev_cx;
}
- hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => {
+ hir::StmtKind::Local(..) => {
// Each declaration introduces a subscope for bindings
// introduced by the declaration; this subscope covers a
// suffix of the block. Each subscope in a block has the
@@ -163,6 +163,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
visitor.cx.var_parent = visitor.cx.parent;
visitor.visit_stmt(statement)
}
+ hir::StmtKind::Item(..) => {
+ // Don't create scopes for items, since they won't be
+ // lowered to THIR and MIR.
+ }
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f5beefc47..77614a9a4 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -24,11 +24,15 @@ use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::misc::{
+ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
+};
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
};
+use rustc_type_ir::TypeFlags;
use std::cell::LazyCell;
use std::ops::{ControlFlow, Deref};
@@ -246,9 +250,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
// `ForeignItem`s are handled separately.
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::TyAlias(hir_ty, ast_generics) => {
- if tcx.features().lazy_type_alias
- || tcx.type_of(item.owner_id).skip_binder().has_opaque_types()
- {
+ if tcx.type_alias_is_lazy(item.owner_id) {
// Bounds of lazy type aliases and of eager ones that contain opaque types are respected.
// E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`.
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
@@ -867,43 +869,65 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
);
});
} else {
- let err_ty_str;
- let mut is_ptr = true;
-
- let err = match ty.kind() {
+ let diag = match ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => {
- is_ptr = false;
- err_ty_str = format!("`{ty}`");
- Some(err_ty_str.as_str())
- }
+ ty::FnPtr(_) => Some(tcx.sess.struct_span_err(
+ hir_ty.span,
+ "using function pointers as const generic parameters is forbidden",
+ )),
+ ty::RawPtr(_) => Some(tcx.sess.struct_span_err(
+ hir_ty.span,
+ "using raw pointers as const generic parameters is forbidden",
+ )),
+ _ => Some(tcx.sess.struct_span_err(
+ hir_ty.span,
+ format!("`{}` is forbidden as the type of a const generic parameter", ty),
+ )),
};
- if let Some(unsupported_type) = err {
- if is_ptr {
- tcx.sess.span_err(
- hir_ty.span,
- format!(
- "using {unsupported_type} as const generic parameters is forbidden",
- ),
- );
- } else {
- let mut err = tcx.sess.struct_span_err(
- hir_ty.span,
- format!(
- "{unsupported_type} is forbidden as the type of a const generic parameter",
- ),
- );
- err.note("the only supported types are integers, `bool` and `char`");
- if tcx.sess.is_nightly_build() {
- err.help(
- "more complex types are supported with `#![feature(adt_const_params)]`",
- );
+ if let Some(mut diag) = diag {
+ diag.note("the only supported types are integers, `bool` and `char`");
+
+ let cause = ObligationCause::misc(hir_ty.span, param.def_id);
+ let may_suggest_feature = match type_allowed_to_implement_const_param_ty(
+ tcx,
+ tcx.param_env(param.def_id),
+ ty,
+ cause,
+ ) {
+ // Can never implement `ConstParamTy`, don't suggest anything.
+ Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false,
+ // May be able to implement `ConstParamTy`. Only emit the feature help
+ // if the type is local, since the user may be able to fix the local type.
+ Err(ConstParamTyImplementationError::InfrigingFields(..)) => {
+ fn ty_is_local(ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Adt(adt_def, ..) => adt_def.did().is_local(),
+ // Arrays and slices use the inner type's `ConstParamTy`.
+ ty::Array(ty, ..) => ty_is_local(*ty),
+ ty::Slice(ty) => ty_is_local(*ty),
+ // `&` references use the inner type's `ConstParamTy`.
+ // `&mut` are not supported.
+ ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty),
+ // Say that a tuple is local if any of its components are local.
+ // This is not strictly correct, but it's likely that the user can fix the local component.
+ ty::Tuple(tys) => tys.iter().any(|ty| ty_is_local(ty)),
+ _ => false,
+ }
+ }
+
+ ty_is_local(ty)
}
- err.emit();
+ // Implments `ConstParamTy`, suggest adding the feature to enable.
+ Ok(..) => true,
+ };
+ if may_suggest_feature && tcx.sess.is_nightly_build() {
+ diag.help(
+ "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types",
+ );
}
+
+ diag.emit();
}
}
}
@@ -1255,7 +1279,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
GenericParamDefKind::Type { has_default, .. }
- | GenericParamDefKind::Const { has_default } => {
+ | GenericParamDefKind::Const { has_default, .. } => {
has_default && def.index >= generics.parent_count as u32
}
GenericParamDefKind::Lifetime => unreachable!(),
@@ -1711,10 +1735,8 @@ fn check_variances_for_type_defn<'tcx>(
}
}
ItemKind::TyAlias(..) => {
- let ty = tcx.type_of(item.owner_id).instantiate_identity();
-
- if tcx.features().lazy_type_alias || ty.has_opaque_types() {
- if ty.references_error() {
+ if tcx.type_alias_is_lazy(item.owner_id) {
+ if tcx.type_of(item.owner_id).skip_binder().references_error() {
return;
}
} else {
@@ -1755,6 +1777,8 @@ fn check_variances_for_type_defn<'tcx>(
.collect::<FxHashSet<_>>()
});
+ let ty_generics = tcx.generics_of(item.owner_id);
+
for (index, _) in variances.iter().enumerate() {
let parameter = Parameter(index as u32);
@@ -1762,13 +1786,27 @@ fn check_variances_for_type_defn<'tcx>(
continue;
}
- let param = &hir_generics.params[index];
+ let ty_param = &ty_generics.params[index];
+ let hir_param = &hir_generics.params[index];
+
+ if ty_param.def_id != hir_param.def_id.into() {
+ // valid programs always have lifetimes before types in the generic parameter list
+ // ty_generics are normalized to be in this required order, and variances are built
+ // from ty generics, not from hir generics. but we need hir generics to get
+ // a span out
+ //
+ // if they aren't in the same order, then the user has written invalid code, and already
+ // got an error about it (or I'm wrong about this)
+ tcx.sess
+ .delay_span_bug(hir_param.span, "hir generics and ty generics in different order");
+ continue;
+ }
- match param.name {
+ match hir_param.name {
hir::ParamName::Error => {}
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
- report_bivariance(tcx, param, has_explicit_bounds);
+ report_bivariance(tcx, hir_param, has_explicit_bounds);
}
}
}
@@ -1825,7 +1863,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
continue;
}
// Match the existing behavior.
- if pred.is_global() && !pred.has_late_bound_vars() {
+ if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
let pred = self.normalize(span, None, pred);
let hir_node = tcx.hir().find_by_def_id(self.body_def_id);
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index c930537d4..be70acfc3 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -1,11 +1,10 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.
-use crate::errors::{
- ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
-};
+use crate::errors;
+
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
@@ -65,7 +64,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
- tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
+ tcx.sess.emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
}
fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
@@ -91,10 +90,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
}
Err(CopyImplementationError::NotAnAdt) => {
- tcx.sess.emit_err(CopyImplOnNonAdt { span });
+ tcx.sess.emit_err(errors::CopyImplOnNonAdt { span });
}
Err(CopyImplementationError::HasDestructor) => {
- tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
+ tcx.sess.emit_err(errors::CopyImplOnTypeWithDtor { span });
}
}
}
@@ -117,7 +116,7 @@ fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId)
infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
}
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
- tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
+ tcx.sess.emit_err(errors::ConstParamTyImplOnNonAdt { span });
}
}
}
@@ -152,11 +151,17 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
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_did);
+ // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
+ // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
+ // that are effectively repr(transparent) newtypes around types that already hav a
+ // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some
+ // of them support an allocator, but we ensure that for the cases where the type implements this
+ // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
+ // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
+ // even if they do not carry that attribute.
use rustc_type_ir::sty::TyKind::*;
match (source.kind(), target.kind()) {
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
@@ -168,22 +173,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
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 `{source_path}`, found `{target_path}`",
- ))
- .emit();
+ tcx.sess.emit_err(errors::DispatchFromDynCoercion {
+ span,
+ trait_name: "DispatchFromDyn",
+ note: true,
+ source_path,
+ target_path,
+ });
return;
}
if def_a.repr().c() || def_a.repr().packed() {
- create_err(
- "structs implementing `DispatchFromDyn` may not have \
- `#[repr(packed)]` or `#[repr(C)]`",
- )
- .emit();
+ tcx.sess.emit_err(errors::DispatchFromDynRepr { span });
}
let fields = &def_a.non_enum_variant().fields;
@@ -195,8 +197,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
let ty_b = field.ty(tcx, args_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
+ if layout.is_1zst() {
+ // ignore 1-ZST fields
return false;
}
}
@@ -205,16 +207,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, 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();
+ tcx.sess.emit_err(errors::DispatchFromDynZST {
+ span,
+ name: field.name,
+ ty: ty_a,
+ });
return false;
}
@@ -225,36 +222,29 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
.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();
+ tcx.sess.emit_err(errors::DispatchFromDynSingle {
+ span,
+ trait_name: "DispatchFromDyn",
+ note: true,
+ });
} 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, args_a),
- field.ty(tcx, args_b),
- )
- })
- .collect::<Vec<_>>()
- .join(", ")
- ))
- .emit();
+ tcx.sess.emit_err(errors::DispatchFromDynMulti {
+ span,
+ coercions_note: true,
+ number: coerced_fields.len(),
+ coercions: coerced_fields
+ .iter()
+ .map(|field| {
+ format!(
+ "`{}` (`{}` to `{}`)",
+ field.name,
+ field.ty(tcx, args_a),
+ field.ty(tcx, args_b),
+ )
+ })
+ .collect::<Vec<_>>()
+ .join(", "),
+ });
} else {
let ocx = ObligationCtxt::new(&infcx);
for field in coerced_fields {
@@ -280,11 +270,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}
}
_ => {
- create_err(
- "the trait `DispatchFromDyn` may only be implemented \
- for a coercion between structures",
- )
- .emit();
+ tcx.sess.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
}
}
}
@@ -351,17 +337,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
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,
+ tcx.sess.emit_err(errors::DispatchFromDynSame {
span,
- E0377,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with the same \
- definition; expected `{}`, found `{}`",
+ trait_name: "CoerceUnsized",
+ note: true,
source_path,
- target_path
- )
- .emit();
+ target_path,
+ });
return err_info;
}
@@ -437,15 +419,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
.collect::<Vec<_>>();
if diff_fields.is_empty() {
- struct_span_err!(
- tcx.sess,
+ tcx.sess.emit_err(errors::CoerceUnsizedOneField {
span,
- E0374,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures with one field \
- being coerced, none found"
- )
- .emit();
+ trait_name: "CoerceUnsized",
+ note: true,
+ });
return err_info;
} else if diff_fields.len() > 1 {
let item = tcx.hir().expect_item(impl_did);
@@ -455,29 +433,17 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
tcx.def_span(impl_did)
};
- struct_span_err!(
- tcx.sess,
+ tcx.sess.emit_err(errors::CoerceUnsizedMulti {
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
+ coercions_note: true,
+ number: diff_fields.len(),
+ coercions: diff_fields
.iter()
- .map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
+ .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
.collect::<Vec<_>>()
- .join(", ")
- ))
- .span_label(span, "requires multiple coercions")
- .emit();
+ .join(", "),
+ });
+
return err_info;
}
@@ -487,14 +453,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
}
_ => {
- struct_span_err!(
- tcx.sess,
- span,
- E0376,
- "the trait `CoerceUnsized` may only be implemented \
- for a coercion between structures"
- )
- .emit();
+ tcx.sess.emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
return err_info;
}
};
@@ -532,13 +491,6 @@ fn infringing_fields_error(
let trait_name = tcx.def_path_str(trait_did);
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0204,
- "the trait `{trait_name}` cannot 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();
@@ -546,14 +498,15 @@ fn infringing_fields_error(
let mut seen_tys = FxHashSet::default();
+ let mut label_spans = Vec::new();
+
for (field, ty, reason) in fields {
// Only report an error once per type.
if !seen_tys.insert(ty) {
continue;
}
- let field_span = tcx.def_span(field.did);
- err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
+ label_spans.push(tcx.def_span(field.did));
match reason {
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
@@ -617,13 +570,24 @@ fn infringing_fields_error(
}
}
}
+ let mut notes = Vec::new();
for ((ty, error_predicate), spans) in errors {
let span: MultiSpan = spans.into();
- err.span_note(
+ notes.push(errors::ImplForTyRequires {
span,
- format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
- );
+ error_predicate,
+ trait_name: trait_name.clone(),
+ ty,
+ });
}
+
+ let mut err = tcx.sess.create_err(errors::TraitCannotImplForTy {
+ span: impl_span,
+ trait_name,
+ label_spans,
+ notes,
+ });
+
suggest_constraining_type_params(
tcx,
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index a94c75f91..0042d683b 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -7,7 +7,6 @@
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::symbol::sym;
+use crate::errors;
+
/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
@@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
impls_map: CrateInherentImpls,
}
-const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
-const INTO_DEFINING_CRATE: &str =
- "consider moving this inherent impl into the crate defining the type if possible";
-const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
- and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-const ADD_ATTR: &str =
- "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
if let Some(ty_def_id) = ty_def_id.as_local() {
@@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> {
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0390,
- "cannot define inherent `impl` for a type outside of the crate where the type is defined",
- )
- .help(INTO_DEFINING_CRATE)
- .span_help(impl_span, ADD_ATTR_TO_TY)
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
return;
}
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0390,
- "cannot define inherent `impl` for a type outside of the crate where the type is defined",
- )
- .help(INTO_DEFINING_CRATE)
- .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
+ span: impl_span,
+ help_span: self.tcx.def_span(impl_item),
+ });
return;
}
}
@@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
} else {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0116,
- "cannot define inherent `impl` for a type outside of the crate \
- where the type is defined"
- )
- .span_label(impl_span, "impl for type defined outside of crate.")
- .note("define and implement a trait or new type instead")
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
}
}
@@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
span,
- E0390,
- "cannot define inherent `impl` for primitive types outside of `core`",
- )
- .help(INTO_CORE)
- .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
- .emit();
+ help_span: self.tcx.def_span(impl_item),
+ });
return;
}
}
} else {
let span = self.tcx.def_span(impl_def_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0390,
- "cannot define inherent `impl` for primitive types",
- );
- err.help("consider using an extension trait instead");
+ let mut note = None;
if let ty::Ref(_, subty, _) = ty.kind() {
- err.note(format!(
- "you could also try moving the reference to \
- uses of `{subty}` (such as `self`) within the implementation"
- ));
+ note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
}
- err.emit();
+ self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
return;
}
}
@@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
}
ty::Dynamic(..) => {
- struct_span_err!(
- self.tcx.sess,
- item_span,
- E0785,
- "cannot define inherent `impl` for a dyn auto trait"
- )
- .span_label(item_span, "impl requires at least one non-auto trait")
- .note("define and implement a new trait or type instead")
- .emit();
+ self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
}
ty::Bool
| ty::Char
@@ -202,23 +151,12 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::FnPtr(_)
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
ty::Alias(..) | ty::Param(_) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- item_span,
- E0118,
- "no nominal type found for inherent implementation"
- );
-
- err.span_label(item_span, "impl requires a nominal type")
- .note("either implement a trait on it or create a newtype to wrap it instead");
-
- err.emit();
+ self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
}
ty::FnDef(..)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index bbdb108c5..69020b1f1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -245,7 +245,6 @@ fn do_orphan_check_impl<'tcx>(
ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..) => {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 7b9f61d7a..221df4e36 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -38,6 +38,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
+use std::ops::Bound;
mod generics_of;
mod item_bounds;
@@ -56,6 +57,8 @@ pub fn provide(providers: &mut Providers) {
resolve_bound_vars::provide(providers);
*providers = Providers {
type_of: type_of::type_of,
+ type_of_opaque: type_of::type_of_opaque,
+ type_alias_is_lazy: type_of::type_alias_is_lazy,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
generics_of: generics_of::generics_of,
@@ -1143,15 +1146,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
}
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
- let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity();
+ let adt_def_id = tcx.hir().get_parent_item(hir_id).def_id.to_def_id();
+ let ty = tcx.type_of(adt_def_id).instantiate_identity();
let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity());
- ty::Binder::dummy(tcx.mk_fn_sig(
- inputs,
- ty,
- false,
- hir::Unsafety::Normal,
- abi::Abi::Rust,
- ))
+ // constructors for structs with `layout_scalar_valid_range` are unsafe to call
+ let safety = match tcx.layout_scalar_valid_range(adt_def_id) {
+ (Bound::Unbounded, Bound::Unbounded) => hir::Unsafety::Normal,
+ _ => hir::Unsafety::Unsafe,
+ };
+ ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust))
}
Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
@@ -1371,7 +1374,7 @@ fn impl_trait_ref(
// make astconv happy.
let mut path_segments = ast_trait_ref.path.segments.to_vec();
let last_segment = path_segments.len() - 1;
- let mut args = path_segments[last_segment].args().clone();
+ let mut args = *path_segments[last_segment].args();
let last_arg = args.args.len() - 1;
assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if tcx.has_attr(anon_const.value.def_id, sym::rustc_host)));
args.args = &args.args[..args.args.len() - 1];
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 484200827..3d60c57b9 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -328,7 +328,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
name: param.name.ident().name,
def_id: param.def_id.to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
- kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
+ kind: ty::GenericParamDefKind::Const {
+ has_default: default.is_some(),
+ is_host_effect: is_host_param,
+ },
})
}
}));
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 495e66366..1298c0860 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -162,8 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
};
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
@@ -189,17 +187,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
predicates.insert((trait_ref.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);
- trace!(?generics);
-
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
// for each const parameter.
@@ -208,10 +195,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// 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 param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id);
let mut bounds = Bounds::default();
// Params are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(
@@ -225,23 +209,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
predicates.extend(bounds.clauses());
trace!(?predicates);
}
- GenericParamKind::Const { .. } => {
- let name = param.name.ident().name;
- let param_const = ty::ParamConst::new(index, name);
-
+ hir::GenericParamKind::Const { .. } => {
let ct_ty = tcx
.type_of(param.def_id.to_def_id())
.no_bound_vars()
.expect("const parameters cannot be generic");
-
- let ct = ty::Const::new_param(tcx, param_const, ct_ty);
-
+ let ct = icx.astconv().hir_id_to_bound_const(param.hir_id, ct_ty);
predicates.insert((
ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
param.span,
));
-
- index += 1;
}
}
}
@@ -252,8 +229,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
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);
-
+ let bound_vars = 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.
@@ -296,7 +272,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
_ => bug!(),
};
let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
- .to_predicate(icx.tcx);
+ .to_predicate(tcx);
(pred, span)
}))
}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 6dd0c840d..eb4466449 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -158,13 +158,14 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
- /// Disallows capturing non-lifetime binders from parent scopes.
+ /// Disallows capturing late-bound vars from parent scopes.
///
/// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
/// since we don't do something more correct like replacing any captured
/// late-bound vars with early-bound params in the const's own generics.
- AnonConstBoundary {
+ LateBoundary {
s: ScopeRef<'a>,
+ what: &'static str,
},
Root {
@@ -216,7 +217,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
- Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(),
+ Scope::LateBoundary { s: _, what } => {
+ f.debug_struct("LateBoundary").field("what", what).finish()
+ }
Scope::Root { opt_parent_item } => {
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
}
@@ -318,7 +321,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
break (vec![], BinderScopeType::Normal);
}
- Scope::ObjectLifetimeDefault { s, .. } | Scope::AnonConstBoundary { s } => {
+ Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => {
scope = s;
}
@@ -697,9 +700,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}) => {
intravisit::walk_ty(self, ty);
- // Elided lifetimes are not allowed in non-return
- // position impl Trait
- let scope = Scope::TraitRefBoundary { s: self.scope };
+ // Elided lifetimes and late-bound lifetimes (from the parent)
+ // are not allowed in non-return position impl Trait
+ let scope = Scope::LateBoundary {
+ s: &Scope::TraitRefBoundary { s: self.scope },
+ what: "type alias impl trait",
+ };
self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
return;
@@ -849,106 +855,87 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
- for param in generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { default, .. } => {
- if let Some(ty) = default {
- this.visit_ty(ty);
- }
- }
- GenericParamKind::Const { ty, default } => {
- this.visit_ty(ty);
- if let Some(default) = default {
- this.visit_body(this.tcx.hir().body(default.body));
- }
- }
- }
+ walk_list!(this, visit_generic_param, generics.params);
+ walk_list!(this, visit_where_predicate, generics.predicates);
+ })
+ }
+
+ fn visit_where_predicate(&mut self, predicate: &'tcx hir::WherePredicate<'tcx>) {
+ match predicate {
+ &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ hir_id,
+ bounded_ty,
+ bounds,
+ bound_generic_params,
+ origin,
+ ..
+ }) => {
+ let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
+ bound_generic_params
+ .iter()
+ .enumerate()
+ .map(|(late_bound_idx, param)| {
+ let pair = ResolvedArg::late(late_bound_idx as u32, param);
+ let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
+ (pair, r)
+ })
+ .unzip();
+ self.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,
+ bound_vars,
+ s: self.scope,
+ scope_type: BinderScopeType::Normal,
+ where_bound_origin: Some(origin),
+ };
+ self.with(scope, |this| {
+ walk_list!(this, visit_generic_param, bound_generic_params);
+ this.visit_ty(&bounded_ty);
+ walk_list!(this, visit_param_bound, bounds);
+ })
}
- for predicate in generics.predicates {
- match predicate {
- &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
- hir_id,
- bounded_ty,
- bounds,
- bound_generic_params,
- origin,
- ..
- }) => {
- let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
- bound_generic_params
- .iter()
- .enumerate()
- .map(|(late_bound_idx, param)| {
- let pair = ResolvedArg::late(late_bound_idx as u32, param);
- let r = late_arg_as_bound_arg(this.tcx, &pair.1, param);
- (pair, r)
- })
- .unzip();
- 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,
- bound_vars,
- s: this.scope,
- scope_type: BinderScopeType::Normal,
- where_bound_origin: Some(origin),
+ &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+ lifetime,
+ bounds,
+ ..
+ }) => {
+ self.visit_lifetime(lifetime);
+ walk_list!(self, visit_param_bound, bounds);
+
+ if lifetime.res != hir::LifetimeName::Static {
+ for bound in bounds {
+ let hir::GenericBound::Outlives(lt) = bound else {
+ continue;
};
- this.with(scope, |this| {
- this.visit_ty(&bounded_ty);
- walk_list!(this, visit_param_bound, bounds);
- })
- }
- &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
- lifetime,
- bounds,
- ..
- }) => {
- this.visit_lifetime(lifetime);
- walk_list!(this, visit_param_bound, bounds);
-
- if lifetime.res != hir::LifetimeName::Static {
- for bound in bounds {
- let hir::GenericBound::Outlives(lt) = bound else {
- continue;
- };
- if lt.res != hir::LifetimeName::Static {
- continue;
- }
- this.insert_lifetime(lt, ResolvedArg::StaticLifetime);
- this.tcx.struct_span_lint_hir(
- lint::builtin::UNUSED_LIFETIMES,
- lifetime.hir_id,
- lifetime.ident.span,
- format!(
- "unnecessary lifetime parameter `{}`",
- lifetime.ident
- ),
- |lint| {
- let help = format!(
- "you can use the `'static` lifetime directly, in place of `{}`",
- lifetime.ident,
- );
- lint.help(help)
- },
- );
- }
+ if lt.res != hir::LifetimeName::Static {
+ continue;
}
- }
- &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
- lhs_ty,
- rhs_ty,
- ..
- }) => {
- this.visit_ty(lhs_ty);
- this.visit_ty(rhs_ty);
+ self.insert_lifetime(lt, ResolvedArg::StaticLifetime);
+ self.tcx.struct_span_lint_hir(
+ lint::builtin::UNUSED_LIFETIMES,
+ lifetime.hir_id,
+ lifetime.ident.span,
+ format!("unnecessary lifetime parameter `{}`", lifetime.ident),
+ |lint| {
+ let help = format!(
+ "you can use the `'static` lifetime directly, in place of `{}`",
+ lifetime.ident,
+ );
+ lint.help(help)
+ },
+ );
}
}
}
- })
+ &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+ self.visit_ty(lhs_ty);
+ self.visit_ty(rhs_ty);
+ }
+ }
}
fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
@@ -982,10 +969,37 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- self.with(Scope::AnonConstBoundary { s: self.scope }, |this| {
+ self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
intravisit::walk_anon_const(this, c);
});
}
+
+ fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
+ match p.kind {
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ self.resolve_type_ref(p.def_id, p.hir_id);
+ }
+ GenericParamKind::Lifetime { .. } => {
+ // No need to resolve lifetime params, we don't use them for things
+ // like implicit `?Sized` or const-param-has-ty predicates.
+ }
+ }
+
+ match p.kind {
+ GenericParamKind::Lifetime { .. } => {}
+ GenericParamKind::Type { default, .. } => {
+ if let Some(ty) = default {
+ self.visit_ty(ty);
+ }
+ }
+ GenericParamKind::Const { ty, default } => {
+ self.visit_ty(ty);
+ if let Some(default) = default {
+ self.visit_body(self.tcx.hir().body(default.body));
+ }
+ }
+ }
+ }
}
fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectLifetimeDefault {
@@ -1165,6 +1179,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut outermost_body = None;
+ let mut crossed_late_boundary = None;
let result = loop {
match *scope {
Scope::Body { id, s } => {
@@ -1197,7 +1212,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
&& let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
&& param.is_elided_lifetime()
- && let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
+ && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
{
let mut diag = rustc_session::parse::feature_err(
@@ -1249,8 +1264,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::TraitRefBoundary { s, .. } => {
+ scope = s;
+ }
+
+ Scope::LateBoundary { s, what } => {
+ crossed_late_boundary = Some(what);
scope = s;
}
}
@@ -1259,6 +1278,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if let Some(mut def) = result {
if let ResolvedArg::EarlyBound(..) = def {
// Do not free early-bound regions, only late-bound ones.
+ } else if let ResolvedArg::LateBound(_, _, param_def_id) = def
+ && let Some(what) = crossed_late_boundary
+ {
+ let use_span = lifetime_ref.ident.span;
+ let def_span = self.tcx.def_span(param_def_id);
+ let guar = match self.tcx.def_kind(param_def_id) {
+ DefKind::LifetimeParam => {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Lifetime {
+ use_span,
+ def_span,
+ what,
+ })
+ }
+ _ => unreachable!(),
+ };
+ def = ResolvedArg::Error(guar);
} else if let Some(body_id) = outermost_body {
let fn_id = self.tcx.hir().body_owner(body_id);
match self.tcx.hir().get(fn_id) {
@@ -1313,7 +1348,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1332,7 +1367,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// search.
let mut late_depth = 0;
let mut scope = self.scope;
- let mut crossed_anon_const = false;
+ let mut crossed_late_boundary = None;
let result = loop {
match *scope {
@@ -1367,28 +1402,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
scope = s;
}
- Scope::AnonConstBoundary { s } => {
- crossed_anon_const = true;
+ Scope::LateBoundary { s, what } => {
+ crossed_late_boundary = Some(what);
scope = s;
}
}
};
if let Some(def) = result {
- if let ResolvedArg::LateBound(..) = def && crossed_anon_const {
+ if let ResolvedArg::LateBound(..) = def
+ && let Some(what) = crossed_late_boundary
+ {
let use_span = self.tcx.hir().span(hir_id);
let def_span = self.tcx.def_span(param_def_id);
let guar = match self.tcx.def_kind(param_def_id) {
DefKind::ConstParam => {
- self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Const {
use_span,
def_span,
+ what,
})
}
DefKind::TyParam => {
- self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type {
+ self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Type {
use_span,
def_span,
+ what,
})
}
_ => unreachable!(),
@@ -1437,7 +1476,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1480,7 +1519,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
DefKind::Struct
| DefKind::Union
| DefKind::Enum
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::Trait,
def_id,
) if depth == 0 => Some(def_id),
@@ -1517,7 +1556,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1822,7 +1861,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
- | Scope::AnonConstBoundary { s } => {
+ | Scope::LateBoundary { s, .. } => {
scope = s;
}
}
@@ -1990,7 +2029,7 @@ fn is_late_bound_map(
hir::TyKind::Path(hir::QPath::Resolved(
None,
- hir::Path { res: Res::Def(DefKind::TyAlias { .. }, alias_def), segments, span },
+ hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
)) => {
// See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
// args to be unconstrained.
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 2bbdbe3a1..ae62119b1 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -1,7 +1,8 @@
use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::HirId;
+use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
@@ -388,86 +389,62 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
},
- Node::Item(item) => {
- match item.kind {
- ItemKind::Static(ty, .., body_id) => {
- if is_suggestable_infer_ty(ty) {
- infer_placeholder_type(
- tcx,
- def_id,
- body_id,
- ty.span,
- item.ident,
- "static variable",
- )
- } else {
- icx.to_ty(ty)
- }
- }
- ItemKind::Const(ty, _, body_id) => {
- if is_suggestable_infer_ty(ty) {
- infer_placeholder_type(
- tcx, def_id, body_id, ty.span, item.ident, "constant",
- )
- } else {
- icx.to_ty(ty)
- }
- }
- ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
- ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
- spans if spans.len() > 0 => {
- let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
- span: spans.into(),
- note: (),
- });
- Ty::new_error(tcx, guar)
- }
- _ => icx.to_ty(*self_ty),
- },
- ItemKind::Fn(..) => {
- let args = ty::GenericArgs::identity_for_item(tcx, def_id);
- Ty::new_fn_def(tcx, def_id.to_def_id(), args)
- }
- ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
- let def = tcx.adt_def(def_id);
- let args = ty::GenericArgs::identity_for_item(tcx, def_id);
- Ty::new_adt(tcx, def, args)
+ Node::Item(item) => match item.kind {
+ ItemKind::Static(ty, .., body_id) => {
+ if is_suggestable_infer_ty(ty) {
+ infer_placeholder_type(
+ tcx,
+ def_id,
+ body_id,
+ ty.span,
+ item.ident,
+ "static variable",
+ )
+ } else {
+ icx.to_ty(ty)
}
- ItemKind::OpaqueTy(OpaqueTy {
- origin: hir::OpaqueTyOrigin::TyAlias { .. },
- ..
- }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
- // Opaque types desugared from `impl Trait`.
- ItemKind::OpaqueTy(&OpaqueTy {
- origin:
- hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
- in_trait,
- ..
- }) => {
- if in_trait && !tcx.defaultness(owner).has_value() {
- span_bug!(
- tcx.def_span(def_id),
- "tried to get type of this RPITIT with no definition"
- );
- }
- opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+ }
+ ItemKind::Const(ty, _, body_id) => {
+ if is_suggestable_infer_ty(ty) {
+ infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
+ } else {
+ icx.to_ty(ty)
}
- ItemKind::Trait(..)
- | ItemKind::TraitAlias(..)
- | ItemKind::Macro(..)
- | ItemKind::Mod(..)
- | ItemKind::ForeignMod { .. }
- | ItemKind::GlobalAsm(..)
- | ItemKind::ExternCrate(..)
- | ItemKind::Use(..) => {
- span_bug!(
- item.span,
- "compute_type_of_item: unexpected item type: {:?}",
- item.kind
- );
+ }
+ ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
+ ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
+ spans if spans.len() > 0 => {
+ let guar = tcx
+ .sess
+ .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
+ Ty::new_error(tcx, guar)
}
+ _ => icx.to_ty(*self_ty),
+ },
+ ItemKind::Fn(..) => {
+ let args = ty::GenericArgs::identity_for_item(tcx, def_id);
+ Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
- }
+ ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
+ let def = tcx.adt_def(def_id);
+ let args = ty::GenericArgs::identity_for_item(tcx, def_id);
+ Ty::new_adt(tcx, def, args)
+ }
+ ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
+ |CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
+ |ty| ty.instantiate_identity(),
+ ),
+ ItemKind::Trait(..)
+ | ItemKind::TraitAlias(..)
+ | ItemKind::Macro(..)
+ | ItemKind::Mod(..)
+ | ItemKind::ForeignMod { .. }
+ | ItemKind::GlobalAsm(..)
+ | ItemKind::ExternCrate(..)
+ | ItemKind::Use(..) => {
+ span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
+ }
+ },
Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => {
@@ -514,6 +491,51 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
ty::EarlyBinder::bind(output)
}
+pub(super) fn type_of_opaque(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
+ if let Some(def_id) = def_id.as_local() {
+ use rustc_hir::*;
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ Ok(ty::EarlyBinder::bind(match tcx.hir().get(hir_id) {
+ Node::Item(item) => match item.kind {
+ ItemKind::OpaqueTy(OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
+ ..
+ }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
+ // Opaque types desugared from `impl Trait`.
+ ItemKind::OpaqueTy(&OpaqueTy {
+ origin:
+ hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
+ in_trait,
+ ..
+ }) => {
+ if in_trait && !tcx.defaultness(owner).has_value() {
+ span_bug!(
+ tcx.def_span(def_id),
+ "tried to get type of this RPITIT with no definition"
+ );
+ }
+ opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+ }
+ _ => {
+ span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
+ }
+ },
+
+ x => {
+ bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
+ }
+ }))
+ } else {
+ // Foreign opaque type will go through the foreign provider
+ // and load the type from metadata.
+ Ok(tcx.type_of(def_id))
+ }
+}
+
fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>,
def_id: LocalDefId,
@@ -601,3 +623,25 @@ fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
.emit();
}
}
+
+pub fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+ use hir::intravisit::Visitor;
+ if tcx.features().lazy_type_alias {
+ return true;
+ }
+ struct HasTait {
+ has_type_alias_impl_trait: bool,
+ }
+ impl<'tcx> Visitor<'tcx> for HasTait {
+ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
+ if let hir::TyKind::OpaqueDef(..) = t.kind {
+ self.has_type_alias_impl_trait = true;
+ } else {
+ hir::intravisit::walk_ty(self, t);
+ }
+ }
+ }
+ let mut has_tait = HasTait { has_type_alias_impl_trait: false };
+ has_tait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0);
+ has_tait.has_type_alias_impl_trait
+}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 957a6bb34..0544c5ca8 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -1,7 +1,7 @@
use rustc_errors::StashKey;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem};
+use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
@@ -74,9 +74,14 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
hidden.ty
} else {
+ let mut parent_def_id = def_id;
+ while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
+ // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
+ parent_def_id = tcx.local_parent(parent_def_id);
+ }
let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
- name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+ name: tcx.item_name(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",
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 9471ad9ca..0efe82b20 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -430,20 +430,30 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> {
}
#[derive(Diagnostic)]
-pub(crate) enum CannotCaptureLateBoundInAnonConst {
- #[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)]
+pub(crate) enum CannotCaptureLateBound {
+ #[diag(hir_analysis_cannot_capture_late_bound_ty)]
Type {
#[primary_span]
use_span: Span,
#[label]
def_span: Span,
+ what: &'static str,
},
- #[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)]
+ #[diag(hir_analysis_cannot_capture_late_bound_const)]
Const {
#[primary_span]
use_span: Span,
#[label]
def_span: Span,
+ what: &'static str,
+ },
+ #[diag(hir_analysis_cannot_capture_late_bound_lifetime)]
+ Lifetime {
+ #[primary_span]
+ use_span: Span,
+ #[label]
+ def_span: Span,
+ what: &'static str,
},
}
@@ -919,6 +929,22 @@ pub struct UnusedAssociatedTypeBounds {
pub span: Span,
}
+#[derive(LintDiagnostic)]
+#[diag(hir_analysis_rpitit_refined)]
+#[note]
+pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
+ #[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")]
+ pub impl_return_span: Span,
+ #[label]
+ pub trait_return_span: Option<Span>,
+ #[label(hir_analysis_unmatched_bound_label)]
+ pub unmatched_bound: Option<Span>,
+
+ pub pre: &'static str,
+ pub post: &'static str,
+ pub return_ty: Ty<'tcx>,
+}
+
#[derive(Diagnostic)]
#[diag(hir_analysis_assoc_bound_on_const)]
#[note]
@@ -927,3 +953,199 @@ pub struct AssocBoundOnConst {
pub span: Span,
pub descr: &'static str,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
+#[help]
+pub struct InherentTyOutside {
+ #[primary_span]
+ #[help(hir_analysis_span_help)]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0378")]
+pub struct DispatchFromDynCoercion<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+ #[note(hir_analysis_coercion_between_struct_same_note)]
+ pub note: bool,
+ pub source_path: String,
+ pub target_path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_dispatch_from_dyn_repr, code = "E0378")]
+pub struct DispatchFromDynRepr {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")]
+#[help]
+pub struct InherentTyOutsideRelevant {
+ #[primary_span]
+ pub span: Span,
+ #[help(hir_analysis_span_help)]
+ pub help_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")]
+#[note]
+pub struct InherentTyOutsideNew {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")]
+#[help]
+pub struct InherentTyOutsidePrimitive {
+ #[primary_span]
+ pub span: Span,
+ #[help(hir_analysis_span_help)]
+ pub help_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")]
+#[help]
+pub struct InherentPrimitiveTy<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub note: Option<InherentPrimitiveTyNote<'a>>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_analysis_inherent_primitive_ty_note)]
+pub struct InherentPrimitiveTyNote<'a> {
+ pub subty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_dyn, code = "E0785")]
+#[note]
+pub struct InherentDyn {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_inherent_nominal, code = "E0118")]
+#[note]
+pub struct InherentNominal {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_dispatch_from_dyn_zst, code = "E0378")]
+#[note]
+pub struct DispatchFromDynZST<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0378")]
+pub struct DispatchFromDynSingle<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+ #[note(hir_analysis_coercion_between_struct_single_note)]
+ pub note: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_dispatch_from_dyn_multi, code = "E0378")]
+#[note]
+pub struct DispatchFromDynMulti {
+ #[primary_span]
+ pub span: Span,
+ #[note(hir_analysis_coercions_note)]
+ pub coercions_note: bool,
+ pub number: usize,
+ pub coercions: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0376")]
+pub struct DispatchFromDynStruct<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0377")]
+pub struct DispatchFromDynSame<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+ #[note(hir_analysis_coercion_between_struct_same_note)]
+ pub note: bool,
+ pub source_path: String,
+ pub target_path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0374")]
+pub struct CoerceUnsizedOneField<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+ #[note(hir_analysis_coercion_between_struct_single_note)]
+ pub note: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_multi, code = "E0375")]
+#[note]
+pub struct CoerceUnsizedMulti {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note(hir_analysis_coercions_note)]
+ pub coercions_note: bool,
+ pub number: usize,
+ pub coercions: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_coerce_unsized_may, code = "E0378")]
+pub struct CoerceUnsizedMay<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_trait_cannot_impl_for_ty, code = "E0204")]
+pub struct TraitCannotImplForTy {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: String,
+ #[label]
+ pub label_spans: Vec<Span>,
+ #[subdiagnostic]
+ pub notes: Vec<ImplForTyRequires>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_analysis_requires_note)]
+pub struct ImplForTyRequires {
+ #[primary_span]
+ pub span: MultiSpan,
+ pub error_predicate: String,
+ pub trait_name: String,
+ pub ty: String,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 4f95174f8..03963925d 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -99,7 +99,6 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::middle;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -107,8 +106,7 @@ use rustc_middle::util;
use rustc_session::parse::feature_err;
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits;
use astconv::{AstConv, OnlySelfBounds};
use bounds::Bounds;
@@ -117,7 +115,7 @@ use rustc_hir::def::DefKind;
fluent_messages! { "../messages.ftl" }
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
- const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
+ const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
const UNSTABLE_EXPLAIN: &str =
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
@@ -151,28 +149,6 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
}
-fn require_same_types<'tcx>(
- tcx: TyCtxt<'tcx>,
- cause: &ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
-) {
- let infcx = &tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(infcx);
- match ocx.eq(cause, param_env, expected, actual) {
- Ok(()) => {
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
- }
- }
- Err(err) => {
- infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
- }
- }
-}
-
pub fn provide(providers: &mut Providers) {
collect::provide(providers);
coherence::provide(providers);
@@ -237,6 +213,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
});
+ // Freeze definitions as we don't add new ones at this point. This improves performance by
+ // allowing lock-free access to them.
+ tcx.untracked().definitions.freeze();
+
// FIXME: Remove this when we implement creating `DefId`s
// for anon constants during their parents' typeck.
// Typeck all body owners in parallel will produce queries
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 8a40509d7..61d9c989e 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -6,7 +6,7 @@
use hir::def_id::{DefId, LocalDefId};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
use super::terms::VarianceTerm::*;
@@ -78,9 +78,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
}
}
DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
- DefKind::TyAlias { lazy }
- if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
- {
+ DefKind::TyAlias if tcx.type_alias_is_lazy(def_id) => {
constraint_cx.build_constraints_for_item(def_id)
}
_ => {}
@@ -110,8 +108,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
// Therefore we need to check the `DefKind` first.
- if let DefKind::TyAlias { lazy } = tcx.def_kind(def_id)
- && (lazy || ty.has_opaque_types())
+ if let DefKind::TyAlias = tcx.def_kind(def_id)
+ && tcx.type_alias_is_lazy(def_id)
{
self.add_constraints_from_ty(current_item, ty, self.covariant);
return;
@@ -314,11 +312,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
// types, where we use Error as the Self type
}
- ty::Placeholder(..)
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
- | ty::Bound(..)
- | ty::Infer(..) => {
+ ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => {
bug!("unexpected type encountered in variance inference: {}", ty);
}
}
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index d91d9fcbc..85e0000ab 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
-use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
/// Defines the `TermsContext` basically houses an arena where we can
@@ -56,9 +56,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
}
- DefKind::TyAlias { lazy }
- if lazy || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() =>
- {
+ DefKind::TyAlias if tcx.type_alias_is_lazy(item_def_id) => {
// These are inferred.
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
@@ -129,7 +127,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
// lifetime generics.
- let mut variances: Vec<_> = std::iter::repeat(ty::Invariant).take(generics.count()).collect();
+ let variances = std::iter::repeat(ty::Invariant).take(generics.count());
+
+ let mut variances: Vec<_> = match tcx.opaque_type_origin(item_def_id) {
+ rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {
+ variances.collect()
+ }
+ // But TAIT are invariant for all generics
+ rustc_hir::OpaqueTyOrigin::TyAlias { .. } => return tcx.arena.alloc_from_iter(variances),
+ };
// Mark all lifetimes from parent generics as unused (Bivariant).
// This will be overridden later if required.
diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs
index 1a8ec5f08..275df2495 100644
--- a/compiler/rustc_hir_analysis/src/variance/terms.rs
+++ b/compiler/rustc_hir_analysis/src/variance/terms.rs
@@ -12,7 +12,7 @@
use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, TyCtxt};
use std::fmt;
use self::VarianceTerm::*;
@@ -97,9 +97,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
}
}
DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
- DefKind::TyAlias { lazy }
- if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() =>
- {
+ DefKind::TyAlias if tcx.type_alias_is_lazy(def_id) => {
terms_cx.add_inferreds_for_item(def_id)
}
_ => {}
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index d57d05d76..d98dc0e6b 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -1,9 +1,24 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
use crate::errors;
pub fn test_variance(tcx: TyCtxt<'_>) {
+ if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
+ for id in tcx.hir().items() {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
+ let variances_of = tcx.variances_of(id.owner_id);
+
+ tcx.sess.emit_err(errors::VariancesOf {
+ span: tcx.def_span(id.owner_id),
+ variances_of: format!("{variances_of:?}"),
+ });
+ }
+ }
+ }
+
// 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() {