Skip to content

Commit 5bbeb16

Browse files
committed
errors handled
1 parent b57081a commit 5bbeb16

4 files changed

Lines changed: 59 additions & 91 deletions

File tree

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only ap
105105
106106
hir_analysis_coerce_same_pat_kind = only pattern types with the same pattern can be coerced between each other
107107
108+
hir_analysis_coerce_shared_multi = implementing `{$trait_name}` does not allow multiple lifetimes or fields to be coerced
109+
110+
hir_analysis_coerce_shared_not_zero = implementing `{$trait_name}` requires that a single lifetime parameter is passed between source and target
111+
108112
hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
109113
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
110114

compiler/rustc_hir_analysis/src/coherence/builtin.rs

Lines changed: 47 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_trait_selection::traits::misc::{
2323
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
2424
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
2525
};
26-
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
26+
use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCause, ObligationCtxt};
2727
use tracing::debug;
2828

2929
use crate::errors;
@@ -463,14 +463,11 @@ pub(crate) fn reborrow_info<'tcx>(
463463
let param_env = tcx.param_env(impl_did);
464464
assert!(!source.has_escaping_bound_vars());
465465

466-
let _cause = ObligationCause::misc(span, impl_did);
467466
let (def, args) = match source.kind() {
468-
&ty::Adt(def, args) if def.is_struct() =>
469-
{
470-
(def, args)
471-
}
467+
&ty::Adt(def, args) if def.is_struct() => (def, args),
472468
_ => {
473-
return Err(tcx.dcx().emit_err(errors::CoerceSharedNonStruct { span, trait_name }));
469+
// Note: reusing error here as it takes trait_name as argument.
470+
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
474471
}
475472
};
476473

@@ -481,43 +478,23 @@ pub(crate) fn reborrow_info<'tcx>(
481478
.iter()
482479
.filter_map(|f| {
483480
// Ignore PhantomData fields
484-
let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
485-
if tcx
486-
.try_normalize_erasing_regions(
487-
ty::TypingEnv::non_body_analysis(tcx, def.did()),
488-
unnormalized_ty,
489-
)
490-
.unwrap_or(unnormalized_ty)
491-
.is_phantom_data()
492-
{
481+
let ty = f.ty(tcx, args);
482+
if ty.is_phantom_data() {
493483
return None;
494484
}
495-
496-
let ty = f.ty(tcx, args);
497-
498-
// Collect up all fields that were significantly changed.
499485
Some((ty, tcx.def_span(f.did)))
500486
})
501487
.collect::<Vec<_>>();
502488

503489
if lifetimes_count != 1 {
504490
let item = tcx.hir_expect_item(impl_did);
505-
let _span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
506-
&item.kind
507-
{
491+
let _span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = &item.kind {
508492
of_trait.trait_ref.path.span
509493
} else {
510494
tcx.def_span(impl_did)
511495
};
512496

513-
todo!();
514-
// let mut lifetimes = args.iter().filter_map(|arg| arg.as_region()).collect::<Vec<_>>();
515-
// return Err(tcx.dcx().emit_err(errors::CoerceMulti {
516-
// span,
517-
// trait_name,
518-
// number: lifetimes_count,
519-
// fields: todo!(),
520-
// }));
497+
return Err(tcx.dcx().emit_err(errors::CoerceSharedMulti { span, trait_name }));
521498
}
522499

523500
if data_fields.is_empty() {
@@ -526,9 +503,23 @@ pub(crate) fn reborrow_info<'tcx>(
526503

527504
// We've found some data fields. They must all be either be Copy or Reborrow.
528505
for (field, span) in data_fields {
529-
assert_field_type_is_reborrow(tcx, &infcx, reborrow_trait, impl_did, param_env, field, span).or_else(|err| {
530-
assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field, span)?;
531-
})
506+
if assert_field_type_is_reborrow(
507+
tcx,
508+
&infcx,
509+
reborrow_trait,
510+
impl_did,
511+
param_env,
512+
field,
513+
span,
514+
)
515+
.is_ok()
516+
{
517+
// Field implements Reborrow.
518+
return Ok(());
519+
}
520+
521+
// Field does not implement Reborrow: it must be Copy.
522+
assert_field_type_is_copy(tcx, &infcx, impl_did, param_env, field, span)?;
532523
}
533524

534525
Ok(())
@@ -542,23 +533,15 @@ fn assert_field_type_is_reborrow<'tcx>(
542533
param_env: ty::ParamEnv<'tcx>,
543534
ty: Ty<'tcx>,
544535
span: Span,
545-
) -> Result<(), ErrorGuaranteed> {
536+
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
546537
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
547538
let cause = traits::ObligationCause::misc(span, impl_did);
548-
let obligation = Obligation::new(
549-
tcx,
550-
cause,
551-
param_env,
552-
ty::TraitRef::new(tcx, reborrow_trait, [ty]),
553-
);
539+
let obligation =
540+
Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, reborrow_trait, [ty]));
554541
ocx.register_obligation(obligation);
555542
let errors = ocx.evaluate_obligations_error_on_ambiguity();
556543

557-
if !errors.is_empty() {
558-
Err(errors)
559-
} else {
560-
Ok(())
561-
}
544+
if !errors.is_empty() { Err(errors) } else { Ok(()) }
562545
}
563546

564547
pub(crate) fn coerce_shared_info<'tcx>(
@@ -591,49 +574,33 @@ pub(crate) fn coerce_shared_info<'tcx>(
591574
let Some((target, _obligations)) =
592575
structurally_normalize_ty(tcx, &infcx, impl_did, span, trait_ref.args.type_at(1))
593576
else {
594-
// return Err(tcx.dcx().emit_err(todo!()));
595-
todo!();
577+
todo!("something went wrong with structurally_normalize_ty");
596578
};
597-
debug!("visit_implementation_of_coerce_shared: {:?} -> {:?} (bound)", source, target);
598579

599580
let param_env = tcx.param_env(impl_did);
600581
assert!(!source.has_escaping_bound_vars());
601582

602-
debug!("visit_implementation_of_coerce_shared: {:?} -> {:?} (free)", source, target);
603-
604-
let _cause = ObligationCause::misc(span, impl_did);
605583
let data = match (source.kind(), target.kind()) {
606584
(&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
607585
if def_a.is_struct() && def_b.is_struct() =>
608586
{
609-
// struct FooMut<'a> { a: u32, b: PhantomData<&'a ()> } -> struct FooRef<'a> { a: u32, b: PhantomData<&'a ()> }
610-
// struct FooMut<'a> { a: u32, b: PhantomData<&'a ()>, c: u32 } -> struct FooRef<'a> { a: u32, b: PhantomData<&'a ()> }
611-
// struct FooMut<'a> { a: u32, b: PhantomData<&'a ()>, c: u32 } -> struct FooRef<'a> { c: u32, a: u32, b: PhantomData<&'a ()> }
612-
613-
// Parent { Child, u32, i32 }, Child { u64, u32 } => ParentRef { ChildRef, u32 }, ChildRef { u64 }
614-
587+
// Check that both A and B have exactly one lifetime argument, and that they have the
588+
// same number of data fields that is not more than 1. The eventual intention is to
589+
// support multiple lifetime arguments (with the reborrowed lifetimes inferred from
590+
// usage one way or another) and multiple data fields with B allowed to leave out fields
591+
// from A. The current state is just the simplest choice.
615592
let a_lifetimes_count = args_a.iter().filter(|arg| arg.as_region().is_some()).count();
616593
let a_data_fields = def_a
617594
.non_enum_variant()
618595
.fields
619596
.iter_enumerated()
620597
.filter_map(|(i, f)| {
621-
// Ignore PhantomData fields
622-
let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
623-
if tcx
624-
.try_normalize_erasing_regions(
625-
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
626-
unnormalized_ty,
627-
)
628-
.unwrap_or(unnormalized_ty)
629-
.is_phantom_data()
630-
{
598+
let a = f.ty(tcx, args_b);
599+
600+
if a.is_phantom_data() {
631601
return None;
632602
}
633603

634-
let a = f.ty(tcx, args_a);
635-
636-
// Collect up all fields that were significantly changed.
637604
Some((i, a, tcx.def_span(f.did)))
638605
})
639606
.collect::<Vec<_>>();
@@ -649,7 +616,6 @@ pub(crate) fn coerce_shared_info<'tcx>(
649616
return None;
650617
}
651618

652-
// Collect up all fields that were significantly changed.
653619
Some((i, b, tcx.def_span(f.did)))
654620
})
655621
.collect::<Vec<_>>();
@@ -669,29 +635,27 @@ pub(crate) fn coerce_shared_info<'tcx>(
669635
tcx.def_span(impl_did)
670636
};
671637

672-
let mut fields = a_data_fields.iter().map(|(_, _, s)| *s).collect::<Vec<_>>();
673-
fields.extend(b_data_fields.iter().map(|(_, _, s)| *s));
674-
return Err(tcx.dcx().emit_err(errors::CoerceMulti {
675-
span,
676-
trait_name,
677-
number: a_data_fields.len() + b_data_fields.len(),
678-
fields: fields.into(),
679-
}));
638+
return Err(tcx.dcx().emit_err(errors::CoerceSharedMulti { span, trait_name }));
680639
}
681640

682641
let kind = ty::adjustment::CoerceSharedInfo {};
683642
if a_data_fields.len() == 1 {
643+
// We found one data field for both: we'll attempt to perform CoerceShared between
644+
// them below.
684645
let (_a_i, a, span_a) = a_data_fields[0];
685646
let (_b_i, b, span_b) = b_data_fields[0];
686647

687648
Some((a, b, coerce_shared_trait, kind, span_a, span_b))
688649
} else {
650+
// We found no data fields in either: this is a reborrowable marker type being
651+
// coerced into a shared marker. That is fine too.
689652
None
690653
}
691654
}
692655

693656
_ => {
694-
return Err(tcx.dcx().emit_err(errors::CoerceSharedNonStruct { span, trait_name }));
657+
// Note: reusing CoerceUnsizedNonStruct error as it takes trait_name as argument.
658+
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
695659
}
696660
};
697661

@@ -746,12 +710,8 @@ fn assert_field_type_is_copy<'tcx>(
746710
let copy_trait = tcx.require_lang_item(LangItem::Copy, span);
747711
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
748712
let cause = traits::ObligationCause::misc(span, impl_did);
749-
let obligation = Obligation::new(
750-
tcx,
751-
cause,
752-
param_env,
753-
ty::TraitRef::new(tcx, copy_trait, [ty]),
754-
);
713+
let obligation =
714+
Obligation::new(tcx, cause, param_env, ty::TraitRef::new(tcx, copy_trait, [ty]));
755715
ocx.register_obligation(obligation);
756716
let errors = ocx.evaluate_obligations_error_on_ambiguity();
757717

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,16 +1230,16 @@ pub(crate) struct CoerceMulti {
12301230
}
12311231

12321232
#[derive(Diagnostic)]
1233-
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
1233+
#[diag(hir_analysis_coerce_shared_not_zero)]
12341234
pub(crate) struct CoerceSharedNotSingleLifetimeParam {
12351235
#[primary_span]
12361236
pub span: Span,
12371237
pub trait_name: &'static str,
12381238
}
12391239

12401240
#[derive(Diagnostic)]
1241-
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
1242-
pub(crate) struct CoerceSharedNonStruct {
1241+
#[diag(hir_analysis_coerce_shared_multi)]
1242+
pub(crate) struct CoerceSharedMulti {
12431243
#[primary_span]
12441244
pub span: Span,
12451245
pub trait_name: &'static str,

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
325325
}
326326
ty::Adt(_, _) if self.tcx.features().reborrow() => {
327327
let reborrow_coerce = self.commit_if_ok(|_| self.coerce_shared_reborrow(a, b));
328-
if reborrow_coerce.is_ok() { reborrow_coerce } else { self.unify(a, b, ForceLeakCheck::No) }
328+
if reborrow_coerce.is_ok() {
329+
reborrow_coerce
330+
} else {
331+
self.unify(a, b, ForceLeakCheck::No)
332+
}
329333
}
330334
_ => {
331335
// Otherwise, just use unification rules.

0 commit comments

Comments
 (0)