]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #106938 - GuillaumeGomez:normalize-projection-field-ty, r=oli-obk
authorbors <bors@rust-lang.org>
Thu, 9 Feb 2023 07:08:19 +0000 (07:08 +0000)
committerbors <bors@rust-lang.org>
Thu, 9 Feb 2023 07:08:19 +0000 (07:08 +0000)
Add missing normalization for union fields types

Overshadows https://github.com/rust-lang/rust/pull/106808.
From the experiment https://github.com/rust-lang/rust/pull/103985.

In short, it allows to use projections as a type for union's fields.

cc `@compiler-errors`
r? `@oli-obk`

1  2 
compiler/rustc_hir_analysis/src/check/check.rs

index 47eace961be55393eee2b53b0c6e5539aebb97c4,248ff1d4cb50633e770f3c46cfc3cc42c5d77591..5e3601efbbe8edf9b44ab825001d51e4dc8c2cb1
@@@ -14,7 -14,7 +14,7 @@@ use rustc_hir::{ItemKind, Node, PathSeg
  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;
 +use rustc_infer::traits::{Obligation, TraitEngineExt as _};
  use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
  use rustc_middle::hir::nested_filter;
  use rustc_middle::middle::stability::EvalResult;
@@@ -28,7 -28,7 +28,7 @@@ 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};
 +use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
  
  use std::ops::ControlFlow;
  
@@@ -121,7 -121,7 +121,7 @@@ fn check_union_fields(tcx: TyCtxt<'_>, 
  
          let param_env = tcx.param_env(item_def_id);
          for field in &def.non_enum_variant().fields {
-             let field_ty = field.ty(tcx, substs);
+             let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, substs));
  
              if !allowed_union_field(field_ty, tcx, param_env) {
                  let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
@@@ -267,7 -267,7 +267,7 @@@ pub(super) fn check_opaque_for_inheriti
          fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
              debug!(?t, "root_visit_ty");
              if t == self.opaque_identity_ty {
 -                ControlFlow::CONTINUE
 +                ControlFlow::Continue(())
              } else {
                  t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
                      tcx: self.tcx,
                  if self.references_parent_regions {
                      ControlFlow::Break(t)
                  } else {
 -                    ControlFlow::CONTINUE
 +                    ControlFlow::Continue(())
                  }
              }
          }
@@@ -412,6 -412,7 +412,6 @@@ fn check_opaque_meets_bounds<'tcx>
      span: Span,
      origin: &hir::OpaqueTyOrigin,
  ) {
 -    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
      let defining_use_anchor = match *origin {
          hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
          hir::OpaqueTyOrigin::TyAlias => def_id,
          _ => re,
      });
  
 -    let misc_cause = traits::ObligationCause::misc(span, hir_id);
 +    let misc_cause = traits::ObligationCause::misc(span, def_id);
  
      match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
          Ok(()) => {}
          Err(ty_err) => {
 +            let ty_err = ty_err.to_string(tcx);
              tcx.sess.delay_span_bug(
                  span,
                  &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
@@@ -531,14 -531,16 +531,14 @@@ fn check_item_type(tcx: TyCtxt<'_>, id
          DefKind::Fn => {} // entirely within check_item_body
          DefKind::Impl => {
              let it = tcx.hir().item(id);
 -            let hir::ItemKind::Impl(ref impl_) = it.kind else {
 -                return;
 -            };
 +            let hir::ItemKind::Impl(impl_) = it.kind else { return };
              debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
              if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
                  check_impl_items_against_trait(
                      tcx,
                      it.span,
                      it.owner_id.def_id,
 -                    impl_trait_ref,
 +                    impl_trait_ref.subst_identity(),
                      &impl_.items,
                  );
                  check_on_unimplemented(tcx, it);
          }
          DefKind::Trait => {
              let it = tcx.hir().item(id);
 -            let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else {
 +            let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
                  return;
              };
              check_on_unimplemented(tcx, it);
  
              for item in items.iter() {
                  let item = tcx.hir().trait_item(item.id);
 -                match item.kind {
 -                    hir::TraitItemKind::Fn(ref sig, _) => {
 +                match &item.kind {
 +                    hir::TraitItemKind::Fn(sig, _) => {
                          let abi = sig.header.abi;
                          fn_maybe_err(tcx, item.ident.span, abi);
                      }
              };
              check_abi(tcx, it.hir_id(), it.span, abi);
  
 -            if abi == Abi::RustIntrinsic {
 -                for item in items {
 -                    let item = tcx.hir().foreign_item(item.id);
 -                    intrinsic::check_intrinsic_type(tcx, item);
 -                }
 -            } else if abi == Abi::PlatformIntrinsic {
 -                for item in items {
 -                    let item = tcx.hir().foreign_item(item.id);
 -                    intrinsic::check_platform_intrinsic_type(tcx, item);
 +            match abi {
 +                Abi::RustIntrinsic => {
 +                    for item in items {
 +                        let item = tcx.hir().foreign_item(item.id);
 +                        intrinsic::check_intrinsic_type(tcx, item);
 +                    }
                  }
 -            } else {
 -                for item in items {
 -                    let def_id = item.id.owner_id.def_id;
 -                    let generics = tcx.generics_of(def_id);
 -                    let own_counts = generics.own_counts();
 -                    if generics.params.len() - own_counts.lifetimes != 0 {
 -                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
 -                            (_, 0) => ("type", "types", Some("u32")),
 -                            // We don't specify an example value, because we can't generate
 -                            // a valid value for any type.
 -                            (0, _) => ("const", "consts", None),
 -                            _ => ("type or const", "types or consts", None),
 -                        };
 -                        struct_span_err!(
 -                            tcx.sess,
 -                            item.span,
 -                            E0044,
 -                            "foreign items may not have {kinds} parameters",
 -                        )
 -                        .span_label(item.span, &format!("can't have {kinds} parameters"))
 -                        .help(
 -                            // FIXME: once we start storing spans for type arguments, turn this
 -                            // into a suggestion.
 -                            &format!(
 -                                "replace the {} parameters with concrete {}{}",
 -                                kinds,
 -                                kinds_pl,
 -                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
 -                            ),
 -                        )
 -                        .emit();
 +
 +                Abi::PlatformIntrinsic => {
 +                    for item in items {
 +                        let item = tcx.hir().foreign_item(item.id);
 +                        intrinsic::check_platform_intrinsic_type(tcx, item);
                      }
 +                }
  
 -                    let item = tcx.hir().foreign_item(item.id);
 -                    match item.kind {
 -                        hir::ForeignItemKind::Fn(ref fn_decl, _, _) => {
 -                            require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
 +                _ => {
 +                    for item in items {
 +                        let def_id = item.id.owner_id.def_id;
 +                        let generics = tcx.generics_of(def_id);
 +                        let own_counts = generics.own_counts();
 +                        if generics.params.len() - own_counts.lifetimes != 0 {
 +                            let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts)
 +                            {
 +                                (_, 0) => ("type", "types", Some("u32")),
 +                                // We don't specify an example value, because we can't generate
 +                                // a valid value for any type.
 +                                (0, _) => ("const", "consts", None),
 +                                _ => ("type or const", "types or consts", None),
 +                            };
 +                            struct_span_err!(
 +                                tcx.sess,
 +                                item.span,
 +                                E0044,
 +                                "foreign items may not have {kinds} parameters",
 +                            )
 +                            .span_label(item.span, &format!("can't have {kinds} parameters"))
 +                            .help(
 +                                // FIXME: once we start storing spans for type arguments, turn this
 +                                // into a suggestion.
 +                                &format!(
 +                                    "replace the {} parameters with concrete {}{}",
 +                                    kinds,
 +                                    kinds_pl,
 +                                    egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
 +                                ),
 +                            )
 +                            .emit();
                          }
 -                        hir::ForeignItemKind::Static(..) => {
 -                            check_static_inhabited(tcx, def_id);
 -                            check_static_linkage(tcx, def_id);
 +
 +                        let item = tcx.hir().foreign_item(item.id);
 +                        match &item.kind {
 +                            hir::ForeignItemKind::Fn(fn_decl, _, _) => {
 +                                require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
 +                            }
 +                            hir::ForeignItemKind::Static(..) => {
 +                                check_static_inhabited(tcx, def_id);
 +                                check_static_linkage(tcx, def_id);
 +                            }
 +                            _ => {}
                          }
 -                        _ => {}
                      }
                  }
              }
          DefKind::GlobalAsm => {
              let it = tcx.hir().item(id);
              let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
 -            InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id());
 +            InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id);
          }
          _ => {}
      }
@@@ -1398,15 -1393,11 +1398,15 @@@ fn async_opaque_type_cycle_error(tcx: T
  ///
  /// If all the return expressions evaluate to `!`, then we explain that the error will go away
  /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
 -fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
 +fn opaque_type_cycle_error(
 +    tcx: TyCtxt<'_>,
 +    opaque_def_id: LocalDefId,
 +    span: Span,
 +) -> ErrorGuaranteed {
      let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
  
      let mut label = false;
 -    if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
 +    if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
          let typeck_results = tcx.typeck(def_id);
          if visitor
              .returns
                  .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
                  .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
              {
 -                struct OpaqueTypeCollector(Vec<DefId>);
 +                #[derive(Default)]
 +                struct OpaqueTypeCollector {
 +                    opaques: Vec<DefId>,
 +                    closures: Vec<DefId>,
 +                }
                  impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
                      fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                          match *t.kind() {
                              ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
 -                                self.0.push(def);
 -                                ControlFlow::CONTINUE
 +                                self.opaques.push(def);
 +                                ControlFlow::Continue(())
 +                            }
 +                            ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
 +                                self.closures.push(def_id);
 +                                t.super_visit_with(self)
                              }
                              _ => t.super_visit_with(self),
                          }
                      }
                  }
 -                let mut visitor = OpaqueTypeCollector(vec![]);
 +
 +                let mut visitor = OpaqueTypeCollector::default();
                  ty.visit_with(&mut visitor);
 -                for def_id in visitor.0 {
 +                for def_id in visitor.opaques {
                      let ty_span = tcx.def_span(def_id);
                      if !seen.contains(&ty_span) {
 -                        err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
 +                        let descr = if ty.is_impl_trait() { "opaque " } else { "" };
 +                        err.span_label(ty_span, &format!("returning this {descr}type `{ty}`"));
                          seen.insert(ty_span);
                      }
                      err.span_label(sp, &format!("returning here with type `{ty}`"));
                  }
 +
 +                for closure_def_id in visitor.closures {
 +                    let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
 +                    let typeck_results = tcx.typeck(closure_local_did);
 +
 +                    let mut label_match = |ty: Ty<'_>, span| {
 +                        for arg in ty.walk() {
 +                            if let ty::GenericArgKind::Type(ty) = arg.unpack()
 +                                && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
 +                                && captured_def_id == opaque_def_id.to_def_id()
 +                            {
 +                                err.span_label(
 +                                    span,
 +                                    format!(
 +                                        "{} captures itself here",
 +                                        tcx.def_kind(closure_def_id).descr(closure_def_id)
 +                                    ),
 +                                );
 +                            }
 +                        }
 +                    };
 +
 +                    // Label any closure upvars that capture the opaque
 +                    for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
 +                    {
 +                        label_match(capture.place.ty(), capture.get_path_span(tcx));
 +                    }
 +                    // Label any generator locals that capture the opaque
 +                    for interior_ty in
 +                        typeck_results.generator_interior_types.as_ref().skip_binder()
 +                    {
 +                        label_match(interior_ty.ty, interior_ty.span);
 +                    }
 +                }
              }
          }
      }
      }
      err.emit()
  }
 +
 +pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 +    debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
 +    debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator));
 +
 +    let typeck = tcx.typeck(def_id);
 +    let param_env = tcx.param_env(def_id);
 +
 +    let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id];
 +    debug!(?generator_interior_predicates);
 +
 +    let infcx = tcx
 +        .infer_ctxt()
 +        // typeck writeback gives us predicates with their regions erased.
 +        // As borrowck already has checked lifetimes, we do not need to do it again.
 +        .ignoring_regions()
 +        // Bind opaque types to `def_id` as they should have been checked by borrowck.
 +        .with_opaque_type_inference(DefiningAnchor::Bind(def_id))
 +        .build();
 +
 +    let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
 +    for (predicate, cause) in generator_interior_predicates {
 +        let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
 +        fulfillment_cx.register_predicate_obligation(&infcx, obligation);
 +    }
 +    let errors = fulfillment_cx.select_all_or_error(&infcx);
 +    debug!(?errors);
 +    if !errors.is_empty() {
 +        infcx.err_ctxt().report_fulfillment_errors(&errors, None);
 +    }
 +}