From 4e8199b572f2035b7749cba276ece3a26630d23e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:21 +0200 Subject: Adding upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_hir_analysis/src/check/check.rs | 263 +++++----- .../rustc_hir_analysis/src/check/compare_method.rs | 576 +++++++++++++-------- compiler/rustc_hir_analysis/src/check/dropck.rs | 39 +- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 17 +- compiler/rustc_hir_analysis/src/check/mod.rs | 6 +- compiler/rustc_hir_analysis/src/check/region.rs | 47 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 220 ++++---- 7 files changed, 671 insertions(+), 497 deletions(-) (limited to 'compiler/rustc_hir_analysis/src/check') 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 { - 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 { - 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)>, } @@ -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 { - 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::>(); + // 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> = 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` // corresponding to their `Vec`, 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`, the - // span points only at the type `Box, 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(®ion.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`, the + // span points only at the type `Box, 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, + 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>( &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(&self, span: Span, loc: Option, 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::>(), - &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>, + wf_tys: &FxIndexSet>, gat_def_id: LocalDefId, gat_generics: &'tcx ty::Generics, ) -> Option>> { @@ -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>, + wf_tys: &FxIndexSet>, 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>, + wf_tys: &FxIndexSet>, 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>, + wf_tys: &FxIndexSet>, 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 { } /// 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>, -{ +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>, - - /// Explicit discriminant of this variant (e.g. `A = 123`), - /// that must evaluate to a constant value. - explicit_discr: Option, -} - -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> { - 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, -- cgit v1.2.3