diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 81 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 204 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/dropck.rs | 8 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsic.rs | 30 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsicck.rs | 9 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/mod.rs | 9 | ||||
-rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 125 |
7 files changed, 256 insertions, 210 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 848828175..0bb98fdf2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,5 +1,5 @@ use crate::check::intrinsicck::InlineAsmCtxt; -use crate::errors::LinkageType; +use crate::errors::{self, LinkageType}; use super::compare_impl_item::check_type_bounds; use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; @@ -22,12 +22,12 @@ 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, AdtDef, DefIdTree, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, + self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, Span}; +use rustc_target::abi::FieldIdx; 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 _; @@ -115,9 +115,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b allowed_union_field(*elem, tcx, param_env) } _ => { - // Fallback case: allow `ManuallyDrop` and things that are `Copy`. + // Fallback case: allow `ManuallyDrop` and things that are `Copy`, + // also no need to report an error if the type is unresolved. ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) || ty.is_copy_modulo_regions(tcx, param_env) + || ty.references_error() } } } @@ -132,26 +134,14 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b Some(Node::Field(field)) => (field.span, field.ty.span), _ => unreachable!("mir field has to correspond to hir field"), }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(errors::InvalidUnionField { field_span, - E0740, - "unions cannot contain fields that may need dropping" - ) - .note( - "a type is guaranteed not to need dropping \ - when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type", - ) - .multipart_suggestion_verbose( - "when the type does not implement `Copy`, \ - wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped", - vec![ - (ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()), - (ty_span.shrink_to_hi(), ">".into()), - ], - Applicability::MaybeIncorrect, - ) - .emit(); + sugg: errors::InvalidUnionFieldSuggestion { + lo: ty_span.shrink_to_lo(), + hi: ty_span.shrink_to_hi(), + }, + note: (), + }); return false; } else if field_ty.needs_drop(tcx, param_env) { // This should never happen. But we can get here e.g. in case of name resolution errors. @@ -222,7 +212,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { return; } - let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); + let substs = InternalSubsts::identity_for_item(tcx, item.owner_id); let span = tcx.def_span(item.owner_id.def_id); if !tcx.features().impl_trait_projections { @@ -315,8 +305,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( .. }) = item.kind { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - let opaque_identity_ty = if in_trait { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { tcx.mk_projection(def_id.to_def_id(), substs) } else { tcx.mk_opaque(def_id.to_def_id(), substs) @@ -455,18 +445,15 @@ fn check_opaque_meets_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } match origin { // Checked when type checking the function containing them. hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} // Can have different predicates to their defining use hir::OpaqueTyOrigin::TyAlias => { - let outlives_environment = OutlivesEnvironment::new(param_env); - let _ = infcx.err_ctxt().check_region_obligations_and_report_errors( - defining_use_anchor, - &outlives_environment, - ); + let outlives_env = OutlivesEnvironment::new(param_env); + let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env); } } // Clean up after ourselves @@ -485,7 +472,7 @@ fn is_enum_of_nonnullable_ptr<'tcx>( let [var_one, var_two] = &adt_def.variants().raw[..] else { return false; }; - let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else { + let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else { return false; }; matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..)) @@ -546,7 +533,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { let trait_substs = - InternalSubsts::identity_for_item(tcx, id.owner_id.to_def_id()); + InternalSubsts::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, @@ -565,10 +552,18 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - check_opaque(tcx, id); + let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) + && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + { + // Skip opaques from RPIT in traits with no default body. + } else { + check_opaque(tcx, id); + } } DefKind::ImplTraitPlaceholder => { - let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id()); + let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id()); // Only check the validity of this opaque type if the function has a default body if let hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), @@ -896,7 +891,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); return; } - let e = fields[0].ty(tcx, substs); + let e = fields[FieldIdx::from_u32(0)].ty(tcx, substs); if !fields.iter().all(|f| f.ty(tcx, substs) == e) { struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") .span_label(sp, "SIMD elements must have the same type") @@ -1172,7 +1167,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { + if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { struct_span_err!( tcx.sess, attr.span, @@ -1511,6 +1506,14 @@ fn opaque_type_cycle_error( { label_match(interior_ty.ty, interior_ty.span); } + if tcx.sess.opts.unstable_opts.drop_tracking_mir + && let DefKind::Generator = tcx.def_kind(closure_def_id) + { + let generator_layout = tcx.mir_generator_witnesses(closure_def_id); + for interior_ty in &generator_layout.field_tys { + label_match(interior_ty.ty, interior_ty.source_info.span); + } + } } } } @@ -1548,6 +1551,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 691d3f8d9..5d119a773 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -16,8 +16,7 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ - self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, + self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; @@ -321,7 +320,7 @@ fn compare_method_predicate_entailment<'tcx>( }); } CheckImpliedWfMode::Skip => { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } } @@ -331,13 +330,8 @@ fn compare_method_predicate_entailment<'tcx>( // lifetime parameters. let outlives_env = OutlivesEnvironment::with_bounds( param_env, - Some(infcx), infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys.clone()), ); - 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 @@ -584,13 +578,13 @@ fn compare_asyncness<'tcx>( #[instrument(skip(tcx), level = "debug", ret)] pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, - def_id: DefId, + impl_m_def_id: LocalDefId, ) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> { - let impl_m = tcx.opt_associated_item(def_id).unwrap(); + let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().subst_identity(); - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(impl_m_def_id); // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during substitution later. @@ -600,7 +594,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_to_impl_substs = impl_trait_ref.substs; - let impl_m_def_id = impl_m.def_id.expect_local(); let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = ObligationCause::new( @@ -721,23 +714,22 @@ pub(super) fn collect_return_position_impl_trait_in_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); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } + let collected_types = collector.types; + // 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_def_id, wf_tys), ); - infcx - .err_ctxt() - .check_region_obligations_and_report_errors(impl_m_def_id, &outlives_environment)?; + ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?; let mut collected_tys = FxHashMap::default(); - for (def_id, (ty, substs)) in collector.types { + for (def_id, (ty, substs)) in collected_types { match infcx.fully_resolve(ty) { Ok(ty) => { // `ty` contains free regions that we created earlier while liberating the @@ -831,7 +823,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, proj) = ty.kind() - && self.interner().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder + && self.interner().is_impl_trait_in_trait(proj.def_id) { if let Some((ty, _)) = self.types.get(&proj.def_id) { return *ty; @@ -1206,6 +1198,17 @@ fn compare_number_of_generics<'tcx>( return Ok(()); } + // We never need to emit a separate error for RPITITs, since if an RPITIT + // has mismatched type or const generic arguments, then the method that it's + // inheriting the generics from will also have mismatched arguments, and + // we'll report an error for that instead. Delay a bug for safety, though. + if tcx.opt_rpitit_info(trait_.def_id).is_some() { + return Err(tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + "errors comparing numbers of generics of trait/impl functions were not emitted", + )); + } + let matchings = [ ("type", trait_own_counts.types, impl_own_counts.types), ("const", trait_own_counts.consts, impl_own_counts.consts), @@ -1732,14 +1735,11 @@ pub(super) fn compare_impl_const_raw( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None)); + return Err(infcx.err_ctxt().report_fulfillment_errors(&errors)); } - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx - .err_ctxt() - .check_region_obligations_and_report_errors(impl_const_item_def, &outlives_environment)?; - Ok(()) + let outlives_env = OutlivesEnvironment::new(param_env); + ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env) } pub(super) fn compare_impl_ty<'tcx>( @@ -1832,19 +1832,14 @@ fn compare_type_predicate_entailment<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let outlives_environment = OutlivesEnvironment::new(param_env); - infcx.err_ctxt().check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, - )?; - - Ok(()) + let outlives_env = OutlivesEnvironment::new(param_env); + ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } /// Validate that `ProjectionCandidate`s created for this associated type will @@ -1867,14 +1862,17 @@ pub(super) fn check_type_bounds<'tcx>( impl_ty: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { + let param_env = tcx.param_env(impl_ty.def_id); + let container_id = impl_ty.container_id(tcx); // Given // // impl<A, B> Foo<u32> for (A, B) { - // type Bar<C> =... + // type Bar<C> = Wrapper<A, B, C> // } // // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` - // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) + // - `normalize_impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) + // - `normalize_impl_ty` would be `Wrapper<A, B, ^0.0>` // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from // the *trait* with the generic associated type parameters (as bound vars). // @@ -1903,56 +1901,46 @@ pub(super) fn check_type_bounds<'tcx>( // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in // the trait (notably, that X: Eq and T: Family). - let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id); - let mut substs = smallvec::SmallVec::with_capacity(defs.count()); - if let Some(def_id) = defs.parent { - let parent_defs = tcx.generics_of(def_id); - InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| { - tcx.mk_param_from_def(param) - }); - } let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(defs.count()); - InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind { - GenericParamDefKind::Type { .. } => { - let kind = ty::BoundTyKind::Param(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Ty(kind); - bound_vars.push(bound_var); - tcx.mk_bound( - ty::INNERMOST, - ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Lifetime => { - let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); - let bound_var = ty::BoundVariableKind::Region(kind); - bound_vars.push(bound_var); - tcx.mk_re_late_bound( - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, - ) - .into() - } - GenericParamDefKind::Const { .. } => { - let bound_var = ty::BoundVariableKind::Const; - bound_vars.push(bound_var); - tcx.mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)), - tcx.type_of(param.def_id).subst_identity(), - ) - .into() - } - }); - let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); - let impl_ty_substs = tcx.mk_substs(&substs); - let container_id = impl_ty.container_id(tcx); - - let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); - let impl_ty_value = tcx.type_of(impl_ty.def_id).subst_identity(); - - let param_env = tcx.param_env(impl_ty.def_id); - + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + // Extend the impl's identity substs with late-bound GAT vars + let normalize_impl_ty_substs = ty::InternalSubsts::identity_for_item(tcx, container_id) + .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { + GenericParamDefKind::Type { .. } => { + let kind = ty::BoundTyKind::Param(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Ty(kind); + bound_vars.push(bound_var); + tcx.mk_bound( + ty::INNERMOST, + ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); + let bound_var = ty::BoundVariableKind::Region(kind); + bound_vars.push(bound_var); + tcx.mk_re_late_bound( + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) + .into() + } + GenericParamDefKind::Const { .. } => { + let bound_var = ty::BoundVariableKind::Const; + bound_vars.push(bound_var); + tcx.mk_const( + ty::ConstKind::Bound( + ty::INNERMOST, + ty::BoundVar::from_usize(bound_vars.len() - 1), + ), + tcx.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into() + } + }); // When checking something like // // trait X { type Y: PartialEq<<Self as X>::Y> } @@ -1962,9 +1950,13 @@ pub(super) fn check_type_bounds<'tcx>( // we want <T as X>::Y to normalize to S. This is valid because we are // checking the default value specifically here. Add this equality to the // ParamEnv for normalization specifically. + let normalize_impl_ty = tcx.type_of(impl_ty.def_id).subst(tcx, normalize_impl_ty_substs); + let rebased_substs = + normalize_impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs); + let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars); let normalize_param_env = { let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>(); - match impl_ty_value.kind() { + match normalize_impl_ty.kind() { ty::Alias(ty::Projection, proj) if proj.def_id == trait_ty.def_id && proj.substs == rebased_substs => { @@ -1978,7 +1970,7 @@ pub(super) fn check_type_bounds<'tcx>( ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs), - term: impl_ty_value.into(), + term: normalize_impl_ty.into(), }, bound_vars, ) @@ -1996,13 +1988,20 @@ pub(super) fn check_type_bounds<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(&infcx); - let impl_ty_span = match tcx.hir().get_by_def_id(impl_ty_def_id) { - hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Type(_, Some(ty)), - .. - }) => ty.span, - hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span, - _ => bug!(), + // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the + // span for an impl's associated type. Instead, for these, use the def_span for the synthesized + // associated type. + let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() { + tcx.def_span(impl_ty_def_id) + } else { + match tcx.hir().get_by_def_id(impl_ty_def_id) { + hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Type(_, Some(ty)), + .. + }) => ty.span, + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span, + _ => bug!(), + } }; let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id); @@ -2023,7 +2022,7 @@ pub(super) fn check_type_bounds<'tcx>( ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; - let obligations = tcx + let obligations: Vec<_> = tcx .bound_explicit_item_bounds(trait_ty.def_id) .subst_iter_copied(tcx, rebased_substs) .map(|(concrete_ty_bound, span)| { @@ -2033,7 +2032,7 @@ pub(super) fn check_type_bounds<'tcx>( .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); - for mut obligation in util::elaborate_obligations(tcx, obligations) { + for mut obligation in util::elaborate(tcx, obligations) { let normalized_predicate = ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); @@ -2045,22 +2044,15 @@ pub(super) fn check_type_bounds<'tcx>( // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors); return Err(reported); } // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types); - let outlives_environment = - OutlivesEnvironment::with_bounds(param_env, Some(&infcx), implied_bounds); - - infcx.err_ctxt().check_region_obligations_and_report_errors( - impl_ty.def_id.expect_local(), - &outlives_environment, - )?; - - Ok(()) + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env) } fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 2bb724138..111bf5e54 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -253,10 +253,6 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { self.tcx } - fn intercrate(&self) -> bool { - false - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -269,10 +265,6 @@ 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 054284cce..854974d16 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>( require_same_types( tcx, &cause, + ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env? tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()), fty, ); @@ -138,14 +139,14 @@ 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, None)), + ty::BoundVariableKind::Region(ty::BrAnon(None)), ty::BoundVariableKind::Region(ty::BrEnv), ]); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { let region = tcx.mk_re_late_bound( ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) }, + ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }, ); let env_region = tcx.mk_re_late_bound( ty::INNERMOST, @@ -222,6 +223,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), + sym::option_payload_ptr => { + let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); + let p0 = param(0); + ( + 1, + vec![tcx.mk_ptr(ty::TypeAndMut { + ty: tcx.mk_adt( + tcx.adt_def(option_def_id), + tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), + ), + mutbl: hir::Mutability::Not, + })], + tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), + ) + } sym::ptr_mask => ( 1, vec![ @@ -300,6 +316,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64), sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32), sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64), + sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32), + sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64), sym::volatile_load | sym::unaligned_volatile_load => { (1, vec![tcx.mk_imm_ptr(param(0))], param(0)) @@ -361,14 +379,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::likely => (0, vec![tcx.types.bool], tcx.types.bool), sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool), + sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)), + sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), ); let discriminant_def_id = assoc_items[0]; - let br = - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) }; + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; ( 1, vec![tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0))], @@ -420,8 +439,7 @@ 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, None) }; + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) }; let param_ty = tcx.mk_imm_ref(tcx.mk_re_late_bound(ty::INNERMOST, br), param(0)); (1, vec![param_ty; 2], tcx.types.bool) } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index b1d5a27be..0d482b53a 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,10 +1,11 @@ use rustc_ast::InlineAsmTemplatePiece; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{Symbol, DUMMY_SP}; +use rustc_target::abi::FieldIdx; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; pub struct InlineAsmCtxt<'a, 'tcx> { @@ -51,7 +52,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { template: &[InlineAsmTemplatePiece], is_input: bool, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>, - target_features: &FxHashSet<Symbol>, + target_features: &FxIndexSet<Symbol>, ) -> Option<InlineAsmType> { let ty = (self.get_operand_ty)(expr); if ty.has_non_region_infer() { @@ -82,7 +83,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } ty::Adt(adt, substs) if adt.repr().simd() => { let fields = &adt.non_enum_variant().fields; - let elem_ty = fields[0].ty(self.tcx, substs); + let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, substs); match elem_ty.kind() { ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => { @@ -201,7 +202,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // (!). In that case we still need the earlier check to verify that the // register class is usable at all. if let Some(feature) = feature { - if !target_features.contains(&feature) { + if !target_features.contains(feature) { let msg = &format!("`{}` target feature is not enabled", feature); let mut err = self.tcx.sess.struct_span_err(expr.span, msg); err.note(&format!( diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 9acfc1b3d..8fe4c44fc 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -109,8 +109,8 @@ pub fn provide(providers: &mut Providers) { }; } -fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { - tcx.calculate_dtor(def_id, dropck::check_drop_impl) +fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> { + tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return @@ -202,8 +202,11 @@ fn missing_items_err( missing_items: &[ty::AssocItem], full_impl_span: Span, ) { + let missing_items = + missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none()); + let missing_items_msg = missing_items - .iter() + .clone() .map(|trait_item| trait_item.name.to_string()) .collect::<Vec<_>>() .join("`, `"); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4cccdf30c..53197bc84 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1,7 +1,6 @@ use crate::autoderef::Autoderef; 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, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -111,16 +110,13 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let errors = wfcx.select_all_or_error(); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(&errors, None); + infcx.err_ctxt().report_fulfillment_errors(&errors); return; } - let outlives_environment = - OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - let _ = infcx - .err_ctxt() - .check_region_obligations_and_report_errors(body_def_id, &outlives_environment); + let _ = wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env); } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) { @@ -676,19 +672,13 @@ fn resolve_regions_with_wf_tys<'tcx>( let infcx = tcx.infer_ctxt().build(); let outlives_environment = OutlivesEnvironment::with_bounds( param_env, - Some(&infcx), infcx.implied_bounds_tys(param_env, id, wf_tys.clone()), ); let region_bound_pairs = outlives_environment.region_bound_pairs(); add_constraints(&infcx, region_bound_pairs); - infcx.process_registered_region_obligations( - outlives_environment.region_bound_pairs(), - param_env, - ); let errors = infcx.resolve_regions(&outlives_environment); - debug!(?errors, "errors"); // If we were able to prove that the type outlives the region without @@ -1033,7 +1023,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // intermediate types must be sized. let needs_drop_copy = || { packed && { - let ty = tcx.type_of(variant.fields.last().unwrap().did).subst_identity(); + let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity(); let ty = tcx.erase_regions(ty); if ty.needs_infer() { tcx.sess @@ -1049,7 +1039,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy(); let unsized_len = if all_sized { 0 } else { 1 }; for (idx, field) in - variant.fields[..variant.fields.len() - unsized_len].iter().enumerate() + variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate() { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); @@ -1545,31 +1535,81 @@ fn check_return_position_impl_trait_in_trait_bounds<'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 - { - for arg in fn_output.walk() { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, proj) = ty.kind() - && tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder - && tcx.impl_trait_in_trait_parent(proj.def_id) == fn_def_id.to_def_id() + let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else { + return; + }; + if assoc_item.container != ty::AssocItemContainer::TraitContainer { + return; + } + fn_output.visit_with(&mut ImplTraitInTraitFinder { + wfcx, + fn_def_id, + depth: ty::INNERMOST, + seen: FxHashSet::default(), + }); +} + +// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering +// strategy, we can't just call `check_associated_item` on the new RPITITs, +// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. +// That's because we need to check that the bounds of the RPITIT hold using +// the special substs that we create during opaque type lowering, otherwise we're +// getting a bunch of early bound and free regions mixed up... Haven't looked too +// deep into this, though. +struct ImplTraitInTraitFinder<'a, 'tcx> { + wfcx: &'a WfCheckingCtxt<'a, 'tcx>, + fn_def_id: LocalDefId, + depth: ty::DebruijnIndex, + seen: FxHashSet<DefId>, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> { + let tcx = self.wfcx.tcx(); + if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() + && self.seen.insert(unshifted_opaque_ty.def_id) + && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() + && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && source == self.fn_def_id + { + let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| { + if let ty::ReLateBound(index, bv) = re.kind() { + if depth != ty::INNERMOST { + return tcx.mk_re_error_with_message( + DUMMY_SP, + "we shouldn't walk non-predicate binders with `impl Trait`...", + ); + } + tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) + } else { + re + } + }); + for (bound, bound_span) in tcx + .bound_explicit_item_bounds(opaque_ty.def_id) + .subst_iter_copied(tcx, opaque_ty.substs) { - let span = tcx.def_span(proj.def_id); - let bounds = wfcx.tcx().explicit_item_bounds(proj.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, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); - wfcx.register_obligations(wf_obligations); + let bound = self.wfcx.normalize(bound_span, None, bound); + self.wfcx.register_obligations(traits::wf::predicate_obligations( + self.wfcx.infcx, + self.wfcx.param_env, + self.wfcx.body_def_id, + bound, + bound_span, + )); + // Set the debruijn index back to innermost here, since we already eagerly + // shifted the substs that we use to generate these bounds. This is unfortunately + // subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`, + // but that function doesn't actually need to normalize the bound it's visiting + // (whereas we have to do so here)... + let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST); + bound.visit_with(self); + self.depth = old_depth; } } + ty.super_visit_with(self) } } @@ -1784,7 +1824,7 @@ fn check_variances_for_type_defn<'tcx>( // Lazily calculated because it is only needed in case of an error. let explicitly_bounded_params = LazyCell::new(|| { - let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id()); + let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.def_id); hir_generics .predicates .iter() @@ -1861,16 +1901,15 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let predicates_with_span = tcx.predicates_of(self.body_def_id).predicates.iter().copied(); // Check elaborated bounds. - let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); + let implied_obligations = traits::elaborate(tcx, predicates_with_span); - for obligation in implied_obligations { + for (pred, obligation_span) in implied_obligations { // We lower empty bounds like `Vec<dyn Copy>:` as // `WellFormed(Vec<dyn Copy>)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { + if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() { continue; } - let pred = obligation.predicate; // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_vars() { let pred = self.normalize(span, None, pred); @@ -1881,8 +1920,6 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { if let Some(hir::Generics { predicates, .. }) = hir_node.and_then(|node| node.generics()) { - let obligation_span = obligation.cause.span(); - span = predicates .iter() // There seems to be no better way to find out which predicate we are in |