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.rs263
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_method.rs576
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs39
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs47
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs220
7 files changed, 671 insertions, 497 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index b70ac0205..fc0ca6209 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,4 +1,5 @@
use crate::check::intrinsicck::InlineAsmCtxt;
+use crate::errors::LinkageType;
use super::compare_method::check_type_bounds;
use super::compare_method::{compare_impl_method, compare_ty_impl};
@@ -6,10 +7,11 @@ use super::*;
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
+use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
@@ -19,13 +21,12 @@ use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{
- self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-};
+use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -75,7 +76,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_simd(tcx, span, def_id);
}
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_packed(tcx, span, def);
}
@@ -83,7 +84,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
}
@@ -230,7 +231,9 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
let span = tcx.def_span(item.owner_id.def_id);
- check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ if !tcx.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).references_error() {
return;
}
@@ -239,6 +242,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
}
+
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
#[instrument(level = "debug", skip(tcx, span))]
@@ -250,39 +254,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);
- struct FoundParentLifetime;
- struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
- impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
- type BreakTy = FoundParentLifetime;
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- debug!("FindParentLifetimeVisitor: r={:?}", r);
- if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
- if index < self.0.parent_count as u32 {
- return ControlFlow::Break(FoundParentLifetime);
- } else {
- return ControlFlow::CONTINUE;
- }
- }
-
- r.super_visit_with(self)
- }
-
- fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ConstKind::Unevaluated(..) = c.kind() {
- // FIXME(#72219) We currently don't detect lifetimes within substs
- // which would violate this check. Even though the particular substitution is not used
- // within the const, this should still be fixed.
- return ControlFlow::CONTINUE;
- }
- c.super_visit_with(self)
- }
- }
-
struct ProhibitOpaqueVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_identity_ty: Ty<'tcx>,
- generics: &'tcx ty::Generics,
+ parent_count: u32,
+ references_parent_regions: bool,
selftys: Vec<(Span, Option<String>)>,
}
@@ -290,12 +266,25 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+ debug!(?t, "root_visit_ty");
if t == self.opaque_identity_ty {
ControlFlow::CONTINUE
} else {
- t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
- .map_break(|FoundParentLifetime| t)
+ 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
+ }
}
}
}
@@ -328,15 +317,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
if let ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+ in_trait,
..
}) = item.kind
{
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ let opaque_identity_ty = if in_trait {
+ tcx.mk_projection(def_id.to_def_id(), substs)
+ } else {
+ tcx.mk_opaque(def_id.to_def_id(), substs)
+ };
let mut visitor = ProhibitOpaqueVisitor {
- opaque_identity_ty: tcx.mk_opaque(
- def_id.to_def_id(),
- InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
- ),
- generics: tcx.generics_of(def_id),
+ opaque_identity_ty,
+ parent_count: tcx.generics_of(def_id).parent_count as u32,
+ references_parent_regions: false,
tcx,
selftys: vec![],
};
@@ -344,10 +338,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
.explicit_item_bounds(def_id)
.iter()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
- debug!(
- "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
- prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
- );
if let Some(ty) = prohibit_opaque.break_value() {
visitor.visit_item(&item);
@@ -358,15 +348,16 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
_ => unreachable!(),
};
- let mut err = struct_span_err!(
- tcx.sess,
+ let mut err = feature_err(
+ &tcx.sess.parse_sess,
+ sym::impl_trait_projections,
span,
- E0760,
- "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
- a parent scope",
- if is_async { "async fn" } else { "impl Trait" },
+ &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,
@@ -450,8 +441,8 @@ fn check_opaque_meets_bounds<'tcx>(
let misc_cause = traits::ObligationCause::misc(span, hir_id);
- match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) {
- Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+ match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
+ Ok(()) => {}
Err(ty_err) => {
tcx.sess.delay_span_bug(
span,
@@ -463,15 +454,14 @@ fn check_opaque_meets_bounds<'tcx>(
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx);
- ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into()));
+ ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
match origin {
// Checked when type checking the function containing them.
@@ -489,6 +479,36 @@ fn check_opaque_meets_bounds<'tcx>(
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
}
+fn is_enum_of_nonnullable_ptr<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ adt_def: AdtDef<'tcx>,
+ substs: SubstsRef<'tcx>,
+) -> bool {
+ if adt_def.repr().inhibit_enum_layout_opt() {
+ return false;
+ }
+
+ let [var_one, var_two] = &adt_def.variants().raw[..] else {
+ return false;
+ };
+ let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else {
+ return false;
+ };
+ matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
+}
+
+fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+ if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
+ if match tcx.type_of(def_id).kind() {
+ ty::RawPtr(_) => false,
+ ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
+ _ => true,
+ } {
+ tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
+ }
+ }
+}
+
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
@@ -501,16 +521,13 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
tcx.ensure().typeck(id.owner_id.def_id);
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
check_static_inhabited(tcx, id.owner_id.def_id);
+ check_static_linkage(tcx, id.owner_id.def_id);
}
DefKind::Const => {
tcx.ensure().typeck(id.owner_id.def_id);
}
DefKind::Enum => {
- let item = tcx.hir().item(id);
- let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
- return;
- };
- check_enum(tcx, &enum_definition.variants, item.owner_id.def_id);
+ check_enum(tcx, id.owner_id.def_id);
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
@@ -642,6 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
}
hir::ForeignItemKind::Static(..) => {
check_static_inhabited(tcx, def_id);
+ check_static_linkage(tcx, def_id);
}
_ => {}
}
@@ -659,7 +677,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
+ let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
@@ -1026,7 +1044,7 @@ pub(super) fn check_packed_inner(
None
}
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
if !adt.repr().transparent() {
return;
}
@@ -1035,14 +1053,14 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
feature_err(
&tcx.sess.parse_sess,
sym::transparent_unions,
- sp,
+ tcx.def_span(adt.did()),
"transparent unions are unstable",
)
.emit();
}
if adt.variants().len() != 1 {
- bad_variant_count(tcx, adt, sp, adt.did());
+ bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
if adt.variants().is_empty() {
// Don't bother checking the fields. No variants (and thus no fields) exist.
return;
@@ -1103,7 +1121,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
.filter_map(|(span, zst, _align1, _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, sp);
+ bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
}
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
@@ -1143,12 +1161,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
}
#[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
+fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
- let sp = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- if vs.is_empty() {
+ if def.variants().is_empty() {
if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
struct_span_err!(
tcx.sess,
@@ -1156,7 +1173,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
E0084,
"unsupported representation for zero-variant enum"
)
- .span_label(sp, "zero-variant enum")
+ .span_label(tcx.def_span(def_id), "zero-variant enum")
.emit();
}
}
@@ -1167,88 +1184,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
feature_err(
&tcx.sess.parse_sess,
sym::repr128,
- sp,
+ tcx.def_span(def_id),
"repr with 128-bit type is unstable",
)
.emit();
}
}
- for v in vs {
- if let Some(ref e) = v.disr_expr {
- tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+ for v in def.variants() {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
+ tcx.ensure().typeck(discr_def_id.expect_local());
}
}
- if tcx.adt_def(def_id).repr().int.is_none() {
- let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
+ if def.repr().int.is_none() {
+ let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));
+ let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
- let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
- let has_non_units = vs.iter().any(|var| !is_unit(var));
- let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
- let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+ let has_non_units = def.variants().iter().any(|var| !is_unit(var));
+ let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
+ let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
if disr_non_unit || (disr_units && has_non_units) {
- let mut err =
- struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+ let mut err = struct_span_err!(
+ tcx.sess,
+ tcx.def_span(def_id),
+ E0732,
+ "`#[repr(inttype)]` must be specified"
+ );
err.emit();
}
}
- detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
-
- check_transparent(tcx, sp, def);
+ detect_discriminant_duplicate(tcx, def);
+ check_transparent(tcx, def);
}
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
-fn detect_discriminant_duplicate<'tcx>(
- tcx: TyCtxt<'tcx>,
- mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
- vs: &'tcx [hir::Variant<'tcx>],
- self_span: Span,
-) {
+fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
- let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
- let var = &vs[idx]; // HIR for the duplicate discriminant
- let (span, display_discr) = match var.disr_expr {
- Some(ref expr) => {
+ let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
+ let var = adt.variant(idx); // HIR for the duplicate discriminant
+ let (span, display_discr) = match var.discr {
+ ty::VariantDiscr::Explicit(discr_def_id) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know
- if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+ if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
+ && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
{
- (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
- // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
} else {
- (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+ // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}`"))
}
}
- None => {
+ // This should not happen.
+ ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
+ ty::VariantDiscr::Relative(distance_to_explicit) => {
// At this point we know this discriminant is a duplicate, and was not explicitly
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
// explicitly assigned discriminant, and letting the user know that this was the
// increment startpoint, and how many steps from there leading to the duplicate
- if let Some((n, hir::Variant { span, ident, .. })) =
- vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+ if let Some(explicit_idx) =
+ idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
{
- let ve_ident = var.ident;
- let n = n + 1;
- let sp = if n > 1 { "variants" } else { "variant" };
+ let explicit_variant = adt.variant(explicit_idx);
+ let ve_ident = var.name;
+ let ex_ident = explicit_variant.name;
+ let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
err.span_label(
- *span,
- format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+ tcx.def_span(explicit_variant.def_id),
+ format!(
+ "discriminant for `{ve_ident}` incremented from this startpoint \
+ (`{ex_ident}` + {distance_to_explicit} {sp} later \
+ => `{ve_ident}` = {dis})"
+ ),
);
}
- (vs[idx].span, format!("`{dis}`"))
+ (tcx.def_span(var.def_id), format!("`{dis}`"))
}
};
err.span_label(span, format!("{display_discr} assigned here"));
};
+ let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
+
// Here we loop through the discriminants, comparing each discriminant to another.
// When a duplicate is detected, we instantiate an error and point to both
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
@@ -1257,29 +1282,29 @@ fn detect_discriminant_duplicate<'tcx>(
// style as we are mutating `discrs` on the fly).
let mut i = 0;
while i < discrs.len() {
- let hir_var_i_idx = discrs[i].0.index();
+ let var_i_idx = discrs[i].0;
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
let mut o = i + 1;
while o < discrs.len() {
- let hir_var_o_idx = discrs[o].0.index();
+ let var_o_idx = discrs[o].0;
if discrs[i].1.val == discrs[o].1.val {
let err = error.get_or_insert_with(|| {
let mut ret = struct_span_err!(
tcx.sess,
- self_span,
+ tcx.def_span(adt.did()),
E0081,
"discriminant value `{}` assigned more than once",
discrs[i].1,
);
- report(discrs[i].1, hir_var_i_idx, &mut ret);
+ report(discrs[i].1, var_i_idx, &mut ret);
ret
});
- report(discrs[o].1, hir_var_o_idx, err);
+ report(discrs[o].1, var_o_idx, err);
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
discrs[o] = *discrs.last().unwrap();
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index 32f66b06f..db150ebf0 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -1,7 +1,7 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -9,13 +9,12 @@ use rustc_hir::intravisit;
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{self, TyCtxtInferExt};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{
- self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+ self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
@@ -50,11 +49,11 @@ pub(crate) fn compare_impl_method<'tcx>(
return;
}
- if let Err(_) = compare_number_of_generics(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+ if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) {
return;
}
- if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
+ if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) {
return;
}
@@ -68,8 +67,14 @@ pub(crate) fn compare_impl_method<'tcx>(
return;
}
- if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
- {
+ if let Err(_) = compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Check,
+ ) {
return;
}
}
@@ -143,10 +148,11 @@ pub(crate) fn compare_impl_method<'tcx>(
#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
fn compare_predicate_entailment<'tcx>(
tcx: TyCtxt<'tcx>,
- impl_m: &AssocItem,
+ impl_m: &ty::AssocItem,
impl_m_span: Span,
- trait_m: &AssocItem,
+ trait_m: &ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
+ check_implied_wf: CheckImpliedWfMode,
) -> Result<(), ErrorGuaranteed> {
let trait_to_impl_substs = impl_trait_ref.substs;
@@ -156,8 +162,7 @@ fn compare_predicate_entailment<'tcx>(
// FIXME(@lcnr): remove that after removing `cause.body_id` from
// obligations.
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- // We sometimes modify the span further down.
- let mut cause = ObligationCause::new(
+ let cause = ObligationCause::new(
impl_m_span,
impl_m_hir_id,
ObligationCauseCode::CompareImplItemObligation {
@@ -175,13 +180,11 @@ fn compare_predicate_entailment<'tcx>(
impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
- let impl_m_generics = tcx.generics_of(impl_m.def_id);
- let trait_m_generics = tcx.generics_of(trait_m.def_id);
let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
// Check region bounds.
- check_region_bounds_on_impl_item(tcx, impl_m, trait_m, &trait_m_generics, &impl_m_generics)?;
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
// Create obligations for each predicate declared by the impl
// definition in the context of the trait's parameter
@@ -220,14 +223,11 @@ fn compare_predicate_entailment<'tcx>(
debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs);
for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) {
let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, normalize_cause, predicate);
+ let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
- ocx.register_obligations(obligations);
let cause = ObligationCause::new(
span,
impl_m_hir_id,
@@ -237,7 +237,7 @@ fn compare_predicate_entailment<'tcx>(
kind: impl_m.kind,
},
);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
// We now need to check that the signature of the impl method is
@@ -256,17 +256,17 @@ fn compare_predicate_entailment<'tcx>(
// Compute placeholder form of impl and trait method tys.
let tcx = infcx.tcx;
- let mut wf_tys = FxHashSet::default();
+ let mut wf_tys = FxIndexSet::default();
- let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
tcx.fn_sig(impl_m.def_id),
);
+ let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let impl_sig = ocx.normalize(norm_cause.clone(), param_env, impl_sig);
- let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+ let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty);
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
@@ -276,7 +276,7 @@ fn compare_predicate_entailment<'tcx>(
// we have to do this before normalization, since the normalized ty may
// not contain the input parameters. See issue #87748.
wf_tys.extend(trait_sig.inputs_and_output.iter());
- let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
+ let trait_sig = ocx.normalize(&norm_cause, param_env, trait_sig);
// We also have to add the normalized trait signature
// as we don't normalize during implied bounds computation.
wf_tys.extend(trait_sig.inputs_and_output.iter());
@@ -290,147 +290,126 @@ fn compare_predicate_entailment<'tcx>(
// type would be more appropriate. In other places we have a `Vec<Span>`
// corresponding to their `Vec<Predicate>`, but we don't have that here.
// Fixing this would improve the output of test `issue-83765.rs`.
- let mut result = infcx
- .at(&cause, param_env)
- .sup(trait_fty, impl_fty)
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
-
- // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
- // RPITITs, we need to equate the output tys instead of just subtyping. If
- // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
- // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
- // fixed up to `ReEmpty`, and which is certainly not what we want.
- if trait_fty.has_infer_types() {
- result = result.and_then(|()| {
- infcx
- .at(&cause, param_env)
- .eq(trait_sig.output(), impl_sig.output())
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
- });
- }
+ let result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
if let Err(terr) = result {
- debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
-
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
-
- cause.span = impl_err_span;
-
- let mut diag = struct_span_err!(
- tcx.sess,
- cause.span(),
- E0053,
- "method `{}` has an incompatible type for trait",
- trait_m.name
- );
- match &terr {
- TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
- {
- let ty = trait_sig.inputs()[0];
- let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
- ExplicitSelf::ByValue => "self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
- ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
- _ => format!("self: {ty}"),
- };
-
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
- // span points only at the type `Box<Self`>, but we want to cover the whole
- // argument pattern and type.
- let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, body) => tcx
- .hir()
- .body_param_names(body)
- .zip(sig.decl.inputs.iter())
- .map(|(param, ty)| param.span.to(ty.span))
- .next()
- .unwrap_or(impl_err_span),
- _ => bug!("{:?} is not a method", impl_m),
- };
-
- diag.span_suggestion(
- span,
- "change the self-receiver type to match the trait",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
- if trait_sig.inputs().len() == *i {
- // Suggestion to change output type. We do not suggest in `async` functions
- // to avoid complex logic or incorrect output.
- match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
- ImplItemKind::Fn(ref sig, _)
- if sig.header.asyncness == hir::IsAsync::NotAsync =>
- {
- let msg = "change the output type to match the trait";
- let ap = Applicability::MachineApplicable;
- match sig.decl.output {
- hir::FnRetTy::DefaultReturn(sp) => {
- let sugg = format!("-> {} ", trait_sig.output());
- diag.span_suggestion_verbose(sp, msg, sugg, ap);
- }
- hir::FnRetTy::Return(hir_ty) => {
- let sugg = trait_sig.output();
- diag.span_suggestion(hir_ty.span, msg, sugg, ap);
- }
- };
- }
- _ => {}
- };
- } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
- diag.span_suggestion(
- impl_err_span,
- "change the parameter type to match the trait",
- trait_ty,
- Applicability::MachineApplicable,
- );
- }
- }
- _ => {}
- }
+ debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
- infcx.err_ctxt().note_type_err(
- &mut diag,
- &cause,
- trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
- Some(infer::ValuePairs::Terms(ExpectedFound {
- expected: trait_fty.into(),
- found: impl_fty.into(),
- })),
+ let emitted = report_trait_method_mismatch(
+ &infcx,
+ cause,
terr,
- false,
- false,
+ (trait_m, trait_fty),
+ (impl_m, impl_fty),
+ trait_sig,
+ impl_trait_ref,
);
+ return Err(emitted);
+ }
- return Err(diag.emit());
+ if check_implied_wf == CheckImpliedWfMode::Check {
+ // We need to check that the impl's args are well-formed given
+ // the hybrid param-env (impl + trait method where-clauses).
+ ocx.register_obligation(traits::Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
+ ));
}
+ let emit_implied_wf_lint = || {
+ infcx.tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
+ impl_m_hir_id,
+ infcx.tcx.def_span(impl_m.def_id),
+ "impl method assumes more implied bounds than the corresponding trait method",
+ |lint| lint,
+ );
+ };
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
- return Err(reported);
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ return Err(reported);
+ }
+ }
}
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
- let outlives_environment = OutlivesEnvironment::with_bounds(
+ let outlives_env = OutlivesEnvironment::with_bounds(
param_env,
Some(infcx),
- infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
+ infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
);
- infcx.check_region_obligations_and_report_errors(
- impl_m.def_id.expect_local(),
- &outlives_environment,
+ infcx.process_registered_region_obligations(
+ outlives_env.region_bound_pairs(),
+ outlives_env.param_env,
);
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
+ // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
+ match check_implied_wf {
+ CheckImpliedWfMode::Check => {
+ return compare_predicate_entailment(
+ tcx,
+ impl_m,
+ impl_m_span,
+ trait_m,
+ impl_trait_ref,
+ CheckImpliedWfMode::Skip,
+ )
+ .map(|()| {
+ // If the skip-mode was successful, emit a lint.
+ emit_implied_wf_lint();
+ });
+ }
+ CheckImpliedWfMode::Skip => {
+ if infcx.tainted_by_errors().is_none() {
+ infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
+ }
+ return Err(tcx
+ .sess
+ .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
+ }
+ }
+ }
Ok(())
}
+#[derive(Debug, PartialEq, Eq)]
+enum CheckImpliedWfMode {
+ /// Checks implied well-formedness of the impl method. If it fails, we will
+ /// re-check with `Skip`, and emit a lint if it succeeds.
+ Check,
+ /// Skips checking implied well-formedness of the impl method, but will emit
+ /// a lint if the `compare_predicate_entailment` succeeded. This means that
+ /// the reason that we had failed earlier during `Check` was due to the impl
+ /// having stronger requirements than the trait.
+ Skip,
+}
+
+#[instrument(skip(tcx), level = "debug", ret)]
pub fn collect_trait_impl_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
@@ -440,6 +419,11 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
let param_env = tcx.param_env(def_id);
+ // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later.
+ compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
+ compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
+ check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+
let trait_to_impl_substs = impl_trait_ref.substs;
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
@@ -464,9 +448,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
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_hir_id);
let impl_sig = ocx.normalize(
- norm_cause.clone(),
+ &norm_cause,
param_env,
infcx.replace_bound_vars_with_fresh_vars(
return_span,
@@ -476,6 +461,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
);
let impl_return_ty = impl_sig.output();
+ // Normalize the trait signature with liberated bound vars, passing it through
+ // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
+ // them with inference variables.
+ // We will use these inference variables to collect the hidden types of RPITITs.
let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
let unnormalized_trait_sig = tcx
.liberate_late_bound_regions(
@@ -483,17 +472,15 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
)
.fold_with(&mut collector);
- let trait_sig = ocx.normalize(norm_cause.clone(), param_env, unnormalized_trait_sig);
+ let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig);
let trait_return_ty = trait_sig.output();
- let wf_tys = FxHashSet::from_iter(
+ let wf_tys = FxIndexSet::from_iter(
unnormalized_trait_sig.inputs_and_output.iter().chain(trait_sig.inputs_and_output.iter()),
);
- match infcx.at(&cause, param_env).eq(trait_return_ty, impl_return_ty) {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
+ match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {
+ Ok(()) => {}
Err(terr) => {
let mut diag = struct_span_err!(
tcx.sess,
@@ -521,23 +508,32 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
}
}
+ debug!(?trait_sig, ?impl_sig, "equating function signatures");
+
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+ let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
+
// Unify the whole function signature. We need to do this to fully infer
// the lifetimes of the return type, but do this after unifying just the
// return types, since we want to avoid duplicating errors from
// `compare_predicate_entailment`.
- match infcx
- .at(&cause, param_env)
- .eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
- {
- Ok(infer::InferOk { value: (), obligations }) => {
- ocx.register_obligations(obligations);
- }
+ match ocx.eq(&cause, param_env, trait_fty, impl_fty) {
+ Ok(()) => {}
Err(terr) => {
- let guar = tcx.sess.delay_span_bug(
- return_span,
- format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
+ // This function gets called during `compare_predicate_entailment` when normalizing a
+ // signature that contains RPITIT. When the method signatures don't match, we have to
+ // emit an error now because `compare_predicate_entailment` will not report the error
+ // when normalization fails.
+ let emitted = report_trait_method_mismatch(
+ infcx,
+ cause,
+ terr,
+ (trait_m, trait_fty),
+ (impl_m, impl_fty),
+ trait_sig,
+ impl_trait_ref,
);
- return Err(guar);
+ return Err(emitted);
}
}
@@ -545,7 +541,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
@@ -597,7 +593,13 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
let num_trait_substs = trait_to_impl_substs.len();
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
let ty = tcx.fold_regions(ty, |region, _| {
- let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
+ match region.kind() {
+ // Remap all free regions, which correspond to late-bound regions in the function.
+ ty::ReFree(_) => {}
+ // Remap early-bound regions as long as they don't come from the `impl` itself.
+ ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
+ _ => return region,
+ }
let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
else {
tcx
@@ -618,11 +620,11 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
collected_tys.insert(def_id, ty);
}
Err(err) => {
- tcx.sess.delay_span_bug(
+ let reported = tcx.sess.delay_span_bug(
return_span,
format!("could not fully resolve: {ty} => {err:?}"),
);
- collected_tys.insert(def_id, tcx.ty_error());
+ collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
}
}
}
@@ -675,12 +677,13 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
for (pred, pred_span) in self.tcx().bound_explicit_item_bounds(proj.item_def_id).subst_iter_copied(self.tcx(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
- ObligationCause::misc(self.span, self.body_id),
+ &ObligationCause::misc(self.span, self.body_id),
self.param_env,
pred,
);
self.ocx.register_obligation(traits::Obligation::new(
+ self.tcx(),
ObligationCause::new(
self.span,
self.body_id,
@@ -697,16 +700,121 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
}
}
+fn report_trait_method_mismatch<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ terr: TypeError<'tcx>,
+ (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>),
+ (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>),
+ trait_sig: ty::FnSig<'tcx>,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> ErrorGuaranteed {
+ let tcx = infcx.tcx;
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
+
+ let mut diag = struct_span_err!(
+ tcx.sess,
+ impl_err_span,
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name
+ );
+ match &terr {
+ TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+ if trait_m.fn_has_self_parameter =>
+ {
+ let ty = trait_sig.inputs()[0];
+ let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
+ ExplicitSelf::ByValue => "self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+ ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
+ _ => format!("self: {ty}"),
+ };
+
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+ // span points only at the type `Box<Self`>, but we want to cover the whole
+ // argument pattern and type.
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, body) => tcx
+ .hir()
+ .body_param_names(body)
+ .zip(sig.decl.inputs.iter())
+ .map(|(param, ty)| param.span.to(ty.span))
+ .next()
+ .unwrap_or(impl_err_span),
+ _ => bug!("{:?} is not a method", impl_m),
+ };
+
+ diag.span_suggestion(
+ span,
+ "change the self-receiver type to match the trait",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+ if trait_sig.inputs().len() == *i {
+ // Suggestion to change output type. We do not suggest in `async` functions
+ // to avoid complex logic or incorrect output.
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
+ ImplItemKind::Fn(ref sig, _) if !sig.header.asyncness.is_async() => {
+ let msg = "change the output type to match the trait";
+ let ap = Applicability::MachineApplicable;
+ match sig.decl.output {
+ hir::FnRetTy::DefaultReturn(sp) => {
+ let sugg = format!("-> {} ", trait_sig.output());
+ diag.span_suggestion_verbose(sp, msg, sugg, ap);
+ }
+ hir::FnRetTy::Return(hir_ty) => {
+ let sugg = trait_sig.output();
+ diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+ }
+ };
+ }
+ _ => {}
+ };
+ } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
+ diag.span_suggestion(
+ impl_err_span,
+ "change the parameter type to match the trait",
+ trait_ty,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ _ => {}
+ }
+
+ cause.span = impl_err_span;
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
+ Some(infer::ValuePairs::Terms(ExpectedFound {
+ expected: trait_fty.into(),
+ found: impl_fty.into(),
+ })),
+ terr,
+ false,
+ false,
+ );
+
+ return diag.emit();
+}
+
fn check_region_bounds_on_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
trait_m: &ty::AssocItem,
- trait_generics: &ty::Generics,
- impl_generics: &ty::Generics,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
- let trait_params = trait_generics.own_counts().lifetimes;
+ let impl_generics = tcx.generics_of(impl_m.def_id);
let impl_params = impl_generics.own_counts().lifetimes;
+ let trait_generics = tcx.generics_of(trait_m.def_id);
+ let trait_params = trait_generics.own_counts().lifetimes;
+
debug!(
"check_region_bounds_on_impl_item: \
trait_generics={:?} \
@@ -729,23 +837,56 @@ fn check_region_bounds_on_impl_item<'tcx>(
.get_generics(impl_m.def_id.expect_local())
.expect("expected impl item to have generics or else we can't compare them")
.span;
- let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() {
- Some(
- tcx.hir()
- .get_generics(local_def_id)
- .expect("expected trait item to have generics or else we can't compare them")
- .span,
- )
- } else {
- None
- };
- let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
- span,
- item_kind: assoc_item_kind_str(impl_m),
- ident: impl_m.ident(tcx),
- generics_span,
- });
+ let mut generics_span = None;
+ let mut bounds_span = vec![];
+ let mut where_span = None;
+ if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id)
+ && let Some(trait_generics) = trait_node.generics()
+ {
+ generics_span = Some(trait_generics.span);
+ // FIXME: we could potentially look at the impl's bounds to not point at bounds that
+ // *are* present in the impl.
+ for p in trait_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(lt) = b {
+ bounds_span.push(lt.ident.span);
+ }
+ }
+ }
+ }
+ if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id)
+ && let Some(impl_generics) = impl_node.generics()
+ {
+ let mut impl_bounds = 0;
+ for p in impl_generics.predicates {
+ if let hir::WherePredicate::BoundPredicate(pred) = p {
+ for b in pred.bounds {
+ if let hir::GenericBound::Outlives(_) = b {
+ impl_bounds += 1;
+ }
+ }
+ }
+ }
+ if impl_bounds == bounds_span.len() {
+ bounds_span = vec![];
+ } else if impl_generics.has_where_clause_predicates {
+ where_span = Some(impl_generics.where_clause_span);
+ }
+ }
+ }
+ let reported = tcx
+ .sess
+ .create_err(LifetimesOrBoundsMismatchOnTrait {
+ span,
+ item_kind: assoc_item_kind_str(impl_m),
+ ident: impl_m.ident(tcx),
+ generics_span,
+ bounds_span,
+ where_span,
+ })
+ .emit_unless(delay);
return Err(reported);
}
@@ -891,9 +1032,9 @@ fn compare_self_type<'tcx>(
fn compare_number_of_generics<'tcx>(
tcx: TyCtxt<'tcx>,
impl_: &ty::AssocItem,
- _impl_span: Span,
trait_: &ty::AssocItem,
trait_span: Option<Span>,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
@@ -1023,7 +1164,7 @@ fn compare_number_of_generics<'tcx>(
err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
}
- let reported = err.emit();
+ let reported = err.emit_unless(delay);
err_occurred = Some(reported);
}
}
@@ -1275,6 +1416,7 @@ fn compare_generic_param_kinds<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: &ty::AssocItem,
trait_item: &ty::AssocItem,
+ delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind);
@@ -1332,7 +1474,7 @@ fn compare_generic_param_kinds<'tcx>(
err.span_label(impl_header_span, "");
err.span_label(param_impl_span, make_param_message("found", param_impl));
- let reported = err.emit();
+ let reported = err.emit_unless(delay);
return Err(reported);
}
}
@@ -1381,18 +1523,15 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
);
// There is no "body" here, so just pass dummy id.
- let impl_ty = ocx.normalize(cause.clone(), param_env, impl_ty);
+ let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
debug!("compare_const_impl: impl_ty={:?}", impl_ty);
- let trait_ty = ocx.normalize(cause.clone(), param_env, trait_ty);
+ let trait_ty = ocx.normalize(&cause, param_env, trait_ty);
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
- let err = infcx
- .at(&cause, param_env)
- .sup(trait_ty, impl_ty)
- .map(|ok| ocx.register_infer_ok_obligations(ok));
+ let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
if let Err(terr) = err {
debug!(
@@ -1441,7 +1580,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
}
// FIXME return `ErrorReported` if region obligations error?
@@ -1461,9 +1600,9 @@ pub(crate) fn compare_ty_impl<'tcx>(
debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
let _: Result<(), ErrorGuaranteed> = (|| {
- compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
+ compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
- compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
+ compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
let sp = tcx.def_span(impl_ty.def_id);
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
@@ -1485,18 +1624,10 @@ fn compare_type_predicate_entailment<'tcx>(
let trait_to_impl_substs =
impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
- let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
- let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
let impl_ty_predicates = tcx.predicates_of(impl_ty.def_id);
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
- check_region_bounds_on_impl_item(
- tcx,
- impl_ty,
- trait_ty,
- &trait_ty_generics,
- &impl_ty_generics,
- )?;
+ check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own(tcx, impl_substs);
@@ -1533,14 +1664,11 @@ fn compare_type_predicate_entailment<'tcx>(
debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds());
- let mut selcx = traits::SelectionContext::new(&infcx);
-
assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
{
let cause = ObligationCause::misc(span, impl_ty_hir_id);
- let traits::Normalized { value: predicate, obligations } =
- traits::normalize(&mut selcx, param_env, cause, predicate);
+ let predicate = ocx.normalize(&cause, param_env, predicate);
let cause = ObligationCause::new(
span,
@@ -1551,15 +1679,14 @@ fn compare_type_predicate_entailment<'tcx>(
kind: impl_ty.kind,
},
);
- ocx.register_obligations(obligations);
- ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
}
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
@@ -1665,13 +1792,10 @@ pub fn check_type_bounds<'tcx>(
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
- tcx.mk_const(ty::ConstS {
- ty: tcx.type_of(param.def_id),
- kind: ty::ConstKind::Bound(
- ty::INNERMOST,
- ty::BoundVar::from_usize(bound_vars.len() - 1),
- ),
- })
+ tcx.mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
+ tcx.type_of(param.def_id),
+ )
.into()
}
});
@@ -1737,7 +1861,6 @@ pub fn check_type_bounds<'tcx>(
let assumed_wf_types =
ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
- let mut selcx = traits::SelectionContext::new(&infcx);
let normalize_cause = ObligationCause::new(
impl_ty_span,
impl_ty_hir_id,
@@ -1760,29 +1883,24 @@ pub fn check_type_bounds<'tcx>(
.subst_iter_copied(tcx, rebased_substs)
.map(|(concrete_ty_bound, span)| {
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
- traits::Obligation::new(mk_cause(span), param_env, concrete_ty_bound)
+ traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
})
.collect();
debug!("check_type_bounds: item_bounds={:?}", obligations);
for mut obligation in util::elaborate_obligations(tcx, obligations) {
- let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
- &mut selcx,
- normalize_param_env,
- normalize_cause.clone(),
- obligation.predicate,
- );
+ let normalized_predicate =
+ ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate);
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
obligation.predicate = normalized_predicate;
- ocx.register_obligations(obligations);
ocx.register_obligation(obligation);
}
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index a74016e22..d6e3ddb0a 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -183,19 +183,27 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let predicate = predicate.kind();
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
- (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
- relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
- }
- (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
- relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
- }
+ (
+ ty::PredicateKind::Clause(ty::Clause::Trait(a)),
+ ty::PredicateKind::Clause(ty::Clause::Trait(b)),
+ ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
+ (
+ ty::PredicateKind::Clause(ty::Clause::Projection(a)),
+ ty::PredicateKind::Clause(ty::Clause::Projection(b)),
+ ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
(
ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(b),
) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
(
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty_a,
+ lt_a,
+ ))),
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty_b,
+ lt_b,
+ ))),
) => {
relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
&& relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
@@ -225,9 +233,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
result
}
-// This is an implementation of the TypeRelation trait with the
-// aim of simply comparing for equality (without side-effects).
-// It is not intended to be used anywhere else other than here.
+/// This is an implementation of the [`TypeRelation`] trait with the
+/// aim of simply comparing for equality (without side-effects).
+///
+/// It is not intended to be used anywhere else other than here.
pub(crate) struct SimpleEqRelation<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -244,6 +253,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
self.tcx
}
+ fn intercrate(&self) -> bool {
+ false
+ }
+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@@ -256,6 +269,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
true
}
+ fn mark_ambiguous(&mut self) {
+ bug!()
+ }
+
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 609095c9c..69e54b41d 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -134,15 +134,18 @@ 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(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
- .iter()
- .copied(),
+ [
+ ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
+ ty::BoundVariableKind::Region(ty::BrEnv),
+ ]
+ .iter()
+ .copied(),
);
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
let region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
));
let env_region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
@@ -364,7 +367,8 @@ 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(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
(
1,
vec![
@@ -418,7 +422,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::raw_eq => {
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let param_ty =
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
(1, vec![param_ty; 2], tcx.types.bool)
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 2e7b10257..29255472a 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -159,7 +159,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
// the consumer's responsibility to ensure all bytes that have been read
// have defined values.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
- && alloc.inner().provenance().len() != 0
+ && alloc.inner().provenance().ptrs().len() != 0
{
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
@@ -309,7 +309,7 @@ fn bounds_from_generic_predicates<'tcx>(
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_predicate) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -318,7 +318,7 @@ fn bounds_from_generic_predicates<'tcx>(
entry.push(trait_predicate.def_id());
}
}
- ty::PredicateKind::Projection(projection_pred) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => {
projections.push(bound_predicate.rebind(projection_pred));
}
_ => {}
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index ff32329e4..b315ebad4 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -241,17 +241,46 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// scopes, meaning that temporaries cannot outlive them.
// This ensures fixed size stacks.
hir::ExprKind::Binary(
- source_map::Spanned { node: hir::BinOpKind::And, .. },
- _,
- ref r,
- )
- | hir::ExprKind::Binary(
- source_map::Spanned { node: hir::BinOpKind::Or, .. },
- _,
+ source_map::Spanned { node: hir::BinOpKind::And | hir::BinOpKind::Or, .. },
+ ref l,
ref r,
) => {
- // For shortcircuiting operators, mark the RHS as a terminating
- // scope since it only executes conditionally.
+ // expr is a short circuiting operator (|| or &&). As its
+ // functionality can't be overridden by traits, it always
+ // processes bool sub-expressions. bools are Copy and thus we
+ // can drop any temporaries in evaluation (read) order
+ // (with the exception of potentially failing let expressions).
+ // We achieve this by enclosing the operands in a terminating
+ // scope, both the LHS and the RHS.
+
+ // We optimize this a little in the presence of chains.
+ // Chains like a && b && c get lowered to AND(AND(a, b), c).
+ // In here, b and c are RHS, while a is the only LHS operand in
+ // that chain. This holds true for longer chains as well: the
+ // leading operand is always the only LHS operand that is not a
+ // binop itself. Putting a binop like AND(a, b) into a
+ // terminating scope is not useful, thus we only put the LHS
+ // into a terminating scope if it is not a binop.
+
+ let terminate_lhs = match l.kind {
+ // let expressions can create temporaries that live on
+ hir::ExprKind::Let(_) => false,
+ // binops already drop their temporaries, so there is no
+ // need to put them into a terminating scope.
+ // This is purely an optimization to reduce the number of
+ // terminating scopes.
+ hir::ExprKind::Binary(
+ source_map::Spanned {
+ node: hir::BinOpKind::And | hir::BinOpKind::Or, ..
+ },
+ ..,
+ ) => false,
+ // otherwise: mark it as terminating
+ _ => true,
+ };
+ if terminate_lhs {
+ terminating(l.hir_id.local_id);
+ }
// `Let` expressions (in a let-chain) shouldn't be terminating, as their temporaries
// should live beyond the immediate expression
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a23575004..b065ace6b 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,7 +1,7 @@
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use hir::def::DefKind;
use rustc_ast as ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -14,13 +14,14 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
- self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
- TypeSuperVisitable, TypeVisitable, TypeVisitor,
+ self, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+ TypeVisitable, TypeVisitor,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -52,12 +53,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
self.ocx.infcx.tcx
}
+ // Convenience function to normalize during wfcheck. This performs
+ // `ObligationCtxt::normalize`, but provides a nice `ObligationCauseCode`.
fn normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
self.ocx.normalize(
- ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)),
+ &ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(loc)),
self.param_env,
value,
)
@@ -74,9 +77,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
// for a type to be WF, we do not need to check if const trait predicates satisfy.
let param_env = self.param_env.without_const();
self.ocx.register_obligation(traits::Obligation::new(
+ self.tcx(),
cause,
param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)),
));
}
}
@@ -104,7 +108,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
f(&mut wfcx);
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return;
}
@@ -116,7 +120,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
}
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
- let node = tcx.hir().expect_owner(def_id);
+ let node = tcx.hir().owner(def_id);
match node {
hir::OwnerNode::Crate(_) => {}
hir::OwnerNode::Item(item) => check_item(tcx, item),
@@ -218,19 +222,16 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
hir::ItemKind::Const(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
}
- hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Struct(_, ref ast_generics) => {
+ check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Union(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
-
+ hir::ItemKind::Enum(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
hir::ItemKind::Trait(..) => {
@@ -414,7 +415,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
.iter()
.copied()
.collect::<Vec<_>>(),
- &FxHashSet::default(),
+ &FxIndexSet::default(),
gat_def_id.def_id,
gat_generics,
)
@@ -463,12 +464,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let mut unsatisfied_bounds: Vec<_> = required_bounds
.into_iter()
.filter(|clause| match clause.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
- !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
- }
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
- !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+ a,
+ b,
+ ))) => {
+ !region_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b)
}
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ a,
+ b,
+ ))) => !ty_known_to_outlive(tcx, gat_hir, param_env, &FxIndexSet::default(), a, b),
_ => bug!("Unexpected PredicateKind"),
})
.map(|clause| clause.to_string())
@@ -549,7 +554,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
param_env: ty::ParamEnv<'tcx>,
item_hir: hir::HirId,
to_check: T,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
gat_def_id: LocalDefId,
gat_generics: &'tcx ty::Generics,
) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
@@ -600,8 +605,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
}));
// The predicate we expect to see. (In our example,
// `Self: 'me`.)
- let clause =
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param));
+ let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
+ ty::OutlivesPredicate(ty_param, region_param),
+ ));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
}
@@ -637,9 +643,8 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
name: region_b_param.name,
}));
// The predicate we expect to see.
- let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
- region_a_param,
- region_b_param,
+ let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
+ ty::OutlivesPredicate(region_a_param, region_b_param),
));
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
bounds.insert(clause);
@@ -656,7 +661,7 @@ fn ty_known_to_outlive<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
) -> bool {
@@ -673,7 +678,7 @@ fn region_known_to_outlive<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
region_a: ty::Region<'tcx>,
region_b: ty::Region<'tcx>,
) -> bool {
@@ -697,7 +702,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
tcx: TyCtxt<'tcx>,
id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
- wf_tys: &FxHashSet<Ty<'tcx>>,
+ wf_tys: &FxIndexSet<Ty<'tcx>>,
add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
) -> bool {
// Unfortunately, we have to use a new `InferCtxt` each call, because
@@ -855,7 +860,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
// Const parameters are well formed if their type is structural match.
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
- let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
+ let ty = tcx.type_of(param.def_id);
if tcx.features().adt_const_params {
if let Some(non_structural_match_ty) =
@@ -1037,27 +1042,25 @@ fn item_adt_kind(kind: &ItemKind<'_>) -> Option<AdtKind> {
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
-fn check_type_defn<'tcx, F>(
- tcx: TyCtxt<'tcx>,
- item: &hir::Item<'tcx>,
- all_sized: bool,
- mut lookup_fields: F,
-) where
- F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
-{
+fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
let _ = tcx.representability(item.owner_id.def_id);
+ let adt_def = tcx.adt_def(item.owner_id);
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
- let variants = lookup_fields(wfcx);
- let packed = tcx.adt_def(item.owner_id).repr().packed();
+ let variants = adt_def.variants();
+ let packed = adt_def.repr().packed();
- for variant in &variants {
+ for variant in variants.iter() {
// All field types must be well-formed.
for field in &variant.fields {
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_wf_obligation(
- field.span,
- Some(WellFormedLoc::Ty(field.def_id)),
- field.ty.into(),
+ hir_ty.span,
+ Some(WellFormedLoc::Ty(field_id)),
+ ty.into(),
)
}
@@ -1065,7 +1068,7 @@ fn check_type_defn<'tcx, F>(
// intermediate types must be sized.
let needs_drop_copy = || {
packed && {
- let ty = variant.fields.last().unwrap().ty;
+ let ty = tcx.type_of(variant.fields.last().unwrap().did);
let ty = tcx.erase_regions(ty);
if ty.needs_infer() {
tcx.sess
@@ -1084,39 +1087,43 @@ fn check_type_defn<'tcx, F>(
variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
{
let last = idx == variant.fields.len() - 1;
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_bound(
traits::ObligationCause::new(
- field.span,
+ hir_ty.span,
wfcx.body_id,
traits::FieldSized {
adt_kind: match item_adt_kind(&item.kind) {
Some(i) => i,
None => bug!(),
},
- span: field.span,
+ span: hir_ty.span,
last,
},
),
wfcx.param_env,
- field.ty,
+ ty,
tcx.require_lang_item(LangItem::Sized, None),
);
}
// Explicit `enum` discriminant values must const-evaluate successfully.
- if let Some(discr_def_id) = variant.explicit_discr {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
traits::MiscObligation,
);
wfcx.register_obligation(traits::Obligation::new(
+ tcx,
cause,
wfcx.param_env,
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
- ty::Const::from_anon_const(tcx, discr_def_id),
- ))
- .to_predicate(tcx),
+ ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
+ )),
));
}
}
@@ -1453,7 +1460,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
wfcx.body_id,
traits::ItemObligation(def_id.to_def_id()),
);
- traits::Obligation::new(cause, wfcx.param_env, pred)
+ traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
});
let predicates = predicates.0.instantiate_identity(tcx);
@@ -1537,23 +1544,50 @@ fn check_fn_or_method<'tcx>(
check_where_clauses(wfcx, span, def_id);
check_return_position_impl_trait_in_trait_bounds(
- tcx,
wfcx,
def_id,
sig.output(),
hir_decl.output.span(),
);
+
+ if sig.abi == Abi::RustCall {
+ let span = tcx.def_span(def_id);
+ let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
+ let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
+ // Check that the argument is a tuple
+ if let Some(ty) = inputs.next() {
+ wfcx.register_bound(
+ ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
+ wfcx.param_env,
+ *ty,
+ tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
+ );
+ } else {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ // No more inputs other than the `self` type and the tuple type
+ if inputs.next().is_some() {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ }
}
/// Basically `check_associated_type_bounds`, but separated for now and should be
/// deduplicated when RPITITs get lowered into real associated items.
+#[tracing::instrument(level = "trace", skip(wfcx))]
fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
- tcx: TyCtxt<'tcx>,
wfcx: &WfCheckingCtxt<'_, 'tcx>,
fn_def_id: LocalDefId,
fn_output: Ty<'tcx>,
span: Span,
) {
+ let tcx = wfcx.tcx();
if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id())
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
{
@@ -1563,8 +1597,10 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>(
&& tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
&& tcx.impl_trait_in_trait_parent(proj.item_def_id) == fn_def_id.to_def_id()
{
+ let span = tcx.def_span(proj.item_def_id);
let bounds = wfcx.tcx().explicit_item_bounds(proj.item_def_id);
let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+ let bound = ty::EarlyBinder(bound).subst(tcx, proj.substs);
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
@@ -1675,14 +1711,13 @@ fn receiver_is_valid<'tcx>(
// `self: Self` is always valid.
if can_eq_self(receiver_ty) {
- if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
}
return true;
}
- let mut autoderef =
- Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty, span);
+ let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_id, span, receiver_ty);
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
if arbitrary_self_types_enabled {
@@ -1692,7 +1727,7 @@ fn receiver_is_valid<'tcx>(
// The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it.
autoderef.next();
- let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, None);
+ let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span));
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
loop {
@@ -1705,9 +1740,7 @@ fn receiver_is_valid<'tcx>(
if can_eq_self(potential_self_ty) {
wfcx.register_obligations(autoderef.into_obligations());
- if let Err(err) =
- wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
- {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
infcx
.err_ctxt()
.report_mismatched_types(&cause, self_ty, potential_self_ty, err)
@@ -1754,13 +1787,9 @@ fn receiver_is_implemented<'tcx>(
receiver_ty: Ty<'tcx>,
) -> bool {
let tcx = wfcx.tcx();
- let trait_ref = ty::Binder::dummy(ty::TraitRef {
- def_id: receiver_trait_def_id,
- substs: tcx.mk_substs_trait(receiver_ty, &[]),
- });
+ let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(receiver_trait_def_id, [receiver_ty]));
- let obligation =
- traits::Obligation::new(cause, wfcx.param_env, trait_ref.without_const().to_predicate(tcx));
+ let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
true
@@ -1907,6 +1936,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
}
let obligation = traits::Obligation::new(
+ tcx,
traits::ObligationCause::new(span, self.body_id, traits::TrivialBound),
empty_env,
pred,
@@ -1925,56 +1955,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
}
-///////////////////////////////////////////////////////////////////////////
-// ADT
-
-// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
-struct AdtVariant<'tcx> {
- /// Types of fields in the variant, that must be well-formed.
- fields: Vec<AdtField<'tcx>>,
-
- /// Explicit discriminant of this variant (e.g. `A = 123`),
- /// that must evaluate to a constant value.
- explicit_discr: Option<LocalDefId>,
-}
-
-struct AdtField<'tcx> {
- ty: Ty<'tcx>,
- def_id: LocalDefId,
- span: Span,
-}
-
-impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
- // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
- fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
- let fields = struct_def
- .fields()
- .iter()
- .map(|field| {
- let def_id = self.tcx().hir().local_def_id(field.hir_id);
- let field_ty = self.tcx().type_of(def_id);
- let field_ty = self.normalize(field.ty.span, None, field_ty);
- debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
- AdtField { ty: field_ty, span: field.ty.span, def_id }
- })
- .collect();
- AdtVariant { fields, explicit_discr: None }
- }
-
- fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
- enum_def
- .variants
- .iter()
- .map(|variant| AdtVariant {
- fields: self.non_enum_variant(&variant.data).fields,
- explicit_discr: variant
- .disr_expr
- .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
- })
- .collect()
- }
-}
-
fn error_392(
tcx: TyCtxt<'_>,
span: Span,