Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 47 additions & 49 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_hir::ItemKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{self, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, PredicateObligations};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::relate::solver_relating::RelateExt;
Expand Down Expand Up @@ -469,37 +469,6 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
}
}

fn structurally_normalize_ty<'tcx>(
tcx: TyCtxt<'tcx>,
infcx: &InferCtxt<'tcx>,
impl_did: LocalDefId,
span: Span,
ty: Unnormalized<'tcx, Ty<'tcx>>,
) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
let ocx = ObligationCtxt::new(infcx);
let Ok(normalized_ty) = ocx.structurally_normalize_ty(
&traits::ObligationCause::misc(span, impl_did),
tcx.param_env(impl_did),
ty,
) else {
// We shouldn't have errors here in the old solver, except for
// evaluate/fulfill mismatches, but that's not a reason for an ICE.
return None;
};
let errors = ocx.try_evaluate_obligations();
if !errors.is_empty() {
if infcx.next_trait_solver() {
unreachable!();
}
// We shouldn't have errors here in the old solver, except for
// evaluate/fulfill mismatches, but that's not a reason for an ICE.
debug!(?errors, "encountered errors while fulfilling");
return None;
}

Some((normalized_ty, ocx.into_pending_obligations()))
}

pub(crate) fn reborrow_info<'tcx>(
tcx: TyCtxt<'tcx>,
impl_did: LocalDefId,
Expand Down Expand Up @@ -552,8 +521,12 @@ pub(crate) fn reborrow_info<'tcx>(
return Ok(());
}

let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
// We've found some data fields. They must all be either be Copy or Reborrow.
for (field, span) in data_fields {
let field = ocx
.deeply_normalize(&traits::ObligationCause::misc(span, impl_did), param_env, field)
.map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
if assert_field_type_is_reborrow(
tcx,
&infcx,
Expand Down Expand Up @@ -620,17 +593,16 @@ pub(crate) fn coerce_shared_info<'tcx>(
}

assert_eq!(trait_ref.def_id, coerce_shared_trait);
let Some((target, _obligations)) = structurally_normalize_ty(
tcx,
&infcx,
impl_did,
span,
Unnormalized::new_wip(trait_ref.args.type_at(1)),
) else {
todo!("something went wrong with structurally_normalize_ty");
};

let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let param_env = tcx.param_env(impl_did);
let (source, target) = ocx
.deeply_normalize(
&traits::ObligationCause::misc(span, impl_did),
param_env,
Unnormalized::new_wip((source, trait_ref.args.type_at(1))),
)
.map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;

assert!(!source.has_escaping_bound_vars());

let data = match (source.kind(), target.kind()) {
Expand Down Expand Up @@ -672,6 +644,20 @@ pub(crate) fn coerce_shared_info<'tcx>(
// them below.
let (a, span_a) = a_data_fields[0];
let (b, span_b) = b_data_fields[0];
let a = ocx
.deeply_normalize(
&traits::ObligationCause::misc(span_a, impl_did),
param_env,
a,
)
.map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
let b = ocx
.deeply_normalize(
&traits::ObligationCause::misc(span_b, impl_did),
param_env,
b,
)
.map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;

Some((a, b, coerce_shared_trait, span_a, span_b))
} else {
Expand All @@ -696,12 +682,19 @@ pub(crate) fn coerce_shared_info<'tcx>(
//
// 1 data field each; they must be the same type and Copy, or relate to one another using
// CoerceShared.
//
// FIXME(reborrow): we should do the relating inside `probe` so the region constraint
// doesn't affect later result in case that this relating fails.
// We should resolve regions if the relating succeeds.
// Besides, the regions of `Ref`s are not checked here so `&'a mut T -> &'static T` is
// allowed.
if source.ref_mutability() == Some(ty::Mutability::Mut)
&& target.ref_mutability() == Some(ty::Mutability::Not)
&& infcx
.eq_structurally_relating_aliases(
.relate(
param_env,
source.peel_refs(),
ty::Variance::Invariant,
target.peel_refs(),
source_field_span,
)
Expand All @@ -710,14 +703,16 @@ pub(crate) fn coerce_shared_info<'tcx>(
// &mut T implements CoerceShared to &T, except not really.
return Ok(());
}

// FIXME(reborrow): we should do the relating inside `probe` so the region constraint
// doesn't affect later result in case that this relating fails.
if infcx
.eq_structurally_relating_aliases(param_env, source, target, source_field_span)
.relate(param_env, source, ty::Variance::Invariant, target, source_field_span)
.is_err()
{
// The two data fields don't agree on a common type; this means
// that they must be `A: CoerceShared<B>`. Register an obligation
// for that.
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
let obligation = Obligation::new(
tcx,
Expand All @@ -735,6 +730,8 @@ pub(crate) fn coerce_shared_info<'tcx>(
ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
} else {
// Types match: check that it is Copy.
//
// FIXME(reborrow): We should resolve regions here.
assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, source, source_field_span)?;
}
}
Expand All @@ -754,19 +751,20 @@ fn generic_lifetime_params_count(args: &[ty::GenericArg<'_>]) -> usize {
args.iter().filter(|arg| arg.as_region().is_some()).count()
}

// FIXME(#155345): This should return `Unnormalized`
fn collect_struct_data_fields<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::AdtDef<'tcx>,
args: ty::GenericArgsRef<'tcx>,
) -> Vec<(Ty<'tcx>, Span)> {
) -> Vec<(Unnormalized<'tcx, Ty<'tcx>>, Span)> {
def.non_enum_variant()
.fields
.iter()
.filter_map(|f| {
// Ignore PhantomData fields
let ty = f.ty(tcx, args).skip_norm_wip();
if ty.is_phantom_data() {
let ty = f.ty(tcx, args);
// FIXME(#155345): alias might be normalized to PhantomData.
// We probably should normalize here instead.
if ty.skip_norm_wip().is_phantom_data() {
return None;
}
Some((ty, tcx.def_span(f.did)))
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/reborrow/coerce-shared-mut-ref-field-validation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//@ check-pass

#![feature(reborrow)]

use std::marker::{CoerceShared, Reborrow};
Expand Down Expand Up @@ -25,7 +27,6 @@ struct AliasRef<'a> {
}

impl<'a> CoerceShared<AliasRef<'a>> for AliasMut<'a> {}
//~^ ERROR

struct InnerLifetimeMut<'a> {
value: &'a mut &'static (),
Expand Down

This file was deleted.

56 changes: 56 additions & 0 deletions tests/ui/reborrow/coerce-shared-normalize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//@ check-pass

// Previously we didn't normalize the source type of `CoerceShared` when
// checking its trait impls.
// We also didn't normalize the types of fields in the wrappers.
// So they fail the trait impl check in `coerce_shared_info` even if
// the normalized types satisfy the requirements.

#![feature(reborrow)]
use std::marker::{CoerceShared, Reborrow};

struct NonParam;

trait HasAssoc<'a> {
type Assoc;
}

struct A;
impl<'a> HasAssoc<'a> for A {
type Assoc = &'a mut NonParam;
}
type MutAlias<'a> = <A as HasAssoc<'a>>::Assoc;

struct B;
impl<'a> HasAssoc<'a> for B {
type Assoc = &'a NonParam;
}
type RefAlias<'a> = <B as HasAssoc<'a>>::Assoc;

struct CustomMut<'a>(MutAlias<'a>);
struct CustomRef<'a>(RefAlias<'a>);

struct C;
impl<'a> HasAssoc<'a> for C {
type Assoc = CustomMut<'a>;
}
type CustomMutAlias<'a> = <C as HasAssoc<'a>>::Assoc;

struct D;
impl<'a> HasAssoc<'a> for D {
type Assoc = CustomRef<'a>;
}
type CustomRefAlias<'a> = <D as HasAssoc<'a>>::Assoc;

impl<'a> Clone for CustomRef<'a> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<'a> Copy for CustomRef<'a> {}


impl<'a> Reborrow for CustomMut<'a> {}
impl<'a> CoerceShared<CustomRefAlias<'a>> for CustomMutAlias<'a> {}

fn main() {}
Loading