summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/check
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
-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
9 files changed, 812 insertions, 367 deletions
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);